들어가며
자바를 공부하다 보면 “추상 클래스”와 “인터페이스”가 헷갈릴 때가 많습니다.
둘 다 추상화(Abstraction) 개념을 구현하는 방법이지만,
그 목적과 쓰임새는 분명히 다릅니다.
이번 글에서는 아래와 같은 차이와 예제를 완벽하게 정리해보겠습니다!
“둘은 어떤 차이가 있을까?”
“언제 추상 클래스를 쓰고, 언제 인터페이스를 써야 할까?”
를 예제와 함께 완벽하게 정리해보겠습니다.
추상화란?
추상화(Abstraction)는 복잡한 현실 세계를 단순화하는 과정입니다.
즉, 필요한 정보만 남기고 불필요한 세부사항은 숨기는 것이죠.
자바에서 추상화는 크게 두 가지 형태로 나타납니다:
- 데이터 추상화 (Data Abstraction) → 데이터 구조를 숨김
- 제어 추상화 (Control Abstraction) → 동작(로직)의 세부 구현을 숨김
그리고 추상 클래스와 인터페이스는 이 중 “제어 추상화”를 표현하는 대표적인 방법입니다.
추상 클래스 (abstract class)
“공통된 속성과 동작을 공유하되, 일부는 하위 클래스가 정의하도록 하는 클래스”
특징
- abstract 키워드 사용
- 상속(extends)을 통해 구현
- 일반 메서드 + 추상 메서드 둘 다 가질 수 있음
- 상태(멤버 변수) 를 가질 수 있음
- 생성자 가짐
- 단일 상속만 가능
예제
abstract class Payment {
abstract void pay(int amount);
void log(int amount) {
System.out.println(amount + "원 결제 완료");
}
}
class CardPayment extends Payment {
@Override
void pay(int amount) {
System.out.println("카드로 " + amount + "원 결제");
log(amount);
}
}
class KakaoPay extends Payment {
@Override
void pay(int amount) {
System.out.println("카카오페이로 " + amount + "원 결제");
log(amount);
}
}
→ 공통된 결제 로직(log)은 상속받고, 결제 방식(pay)만 다르게 구현.
인터페이스 (interface)
“공통된 동작을 정의하는 규약(명세서)”
특징
- interface 키워드 사용
- 구현(implements) 을 통해 구현
- 원래는 오직 추상 메서드와 상수만 포함 가능했지만
Java 8 이후 default, static 메서드,
Java 9 이후 private 메서드도 가능 - 다중 구현 가능
예제
interface Notifier {
void send(String message);
}
class EmailNotifier implements Notifier {
public void send(String message) {
System.out.println("이메일 발송: " + message);
}
}
class SMSNotifier implements Notifier {
public void send(String message) {
System.out.println("문자 발송: " + message);
}
}
public class Main {
public static void main(String[] args) {
Notifier n1 = new EmailNotifier();
Notifier n2 = new SMSNotifier();
n1.send("안녕하세요!");
n2.send("오늘은 좋은 하루!");
}
}
→ 서로 다른 클래스지만, 같은 인터페이스를 통해 동일한 동작 수행 가능!
추상 클래스 vs 인터페이스 비교 정리
구분 추상 클래스 인터페이스
| 키워드 | abstract class | interface |
| 상속 방식 | extends (단일 상속) | implements (다중 구현 가능) |
| 구성 요소 | 변수, 생성자, 일반 + 추상 메서드 | 상수, 추상 메서드, default/static 메서드 |
| 상태(필드) 보유 | 가능 | 불가능 (상수만 가능) |
| 생성자 | 있음 | 없음 |
| 목적 | 공통된 속성과 동작 제공 | 규약(계약) 제공 |
| 관계 표현 | “A는 B의 일종이다 (is-a)” | “A는 B의 기능을 가진다 (can-do)” |
| 사용 예시 | 여러 클래스가 비슷한 구조를 가질 때 | 서로 다른 클래스가 같은 기능을 수행할 때 |
둘을 함께 쓰는 경우
실무에서는 종종 추상 클래스 + 인터페이스를 함께 사용합니다.
interface Authenticatable {
boolean authenticate(String token);
}
abstract class User {
String name;
abstract void login();
}
class AdminUser extends User implements Authenticatable {
void login() {
System.out.println("관리자 로그인");
}
public boolean authenticate(String token) {
return token.equals("admin-token");
}
}
➡️ User는 공통 속성과 기본 틀을 제공,
➡️ Authenticatable은 인증 규약을 명시.
➡️ 둘을 조합하면 구조적 일관성과 유연성을 동시에 얻을 수 있음.
Java 8 이후 인터페이스가 강력해진 이유
인터페이스에 default 메서드가 추가된 이유는
기존 구현체들과의 하위 호환성 때문입니다.
예를 들어, 기존에 List 인터페이스에 새로운 기능을 추가하고 싶어도
모든 구현체(ArrayList, LinkedList 등)에 일일이 코드를 추가할 수 없었죠.
이 문제를 해결하기 위해 default 메서드가 생겼습니다.
interface Logger {
default void log(String msg) {
System.out.println("로그: " + msg);
}
}
➡️ 인터페이스도 이제 “부분 구현”이 가능해지면서
추상 클래스와의 경계가 조금 흐려졌다는 점이 포인트입니다.
언제 어떤 걸 써야 할까?
상황별 추천하는 방법
| 여러 클래스가 공통 속성(필드)과 로직을 공유 | 추상 클래스 |
| 서로 다른 클래스들이 동일한 기능을 수행해야 함 | 인터페이스 |
| 다중 상속 구조가 필요함 | 인터페이스 |
| 기본 구현 + 확장성을 둘 다 원함 | 추상 클래스 + 인터페이스 조합 |
마무리
추상 클래스와 인터페이스는 둘 다 “추상화”를 구현하지만
목적이 다르다는 점이 핵심입니다.
- 추상 클래스: 공통 기반 제공 (상속 중심)
- 인터페이스: 행동 규약 제공 (다형성 중심)
둘을 제대로 구분하고 조합할 수 있다면,
코드의 재사용성·유연성·확장성이 눈에 띄게 올라갑니다.

'Java' 카테고리의 다른 글
| [JAVA] 객체지향개념Ⅱ (0) | 2025.10.13 |
|---|---|
| [Java] 문자열 처리 성능비교 - String vs StringBuilder vs StringBuffer (0) | 2025.10.11 |
| [JAVA] 데이터 추상화 vs 제어 추상화 (0) | 2025.10.09 |
| [Java] 객체지향개념I (0) | 2025.10.08 |
| [Java] 클래스 메소드(static 메소드) vs 인스턴스 메소드 (0) | 2025.10.03 |