Java 문법을 공부하다 보면 abstract 과 interface가 나란히 등장한다.
처음엔 이렇게 느꼈다.
- 추상 클래스는 상속받아 확장해서 쓰니까 유용하네.
- 그런데 인터페이스는 다중 구현도 되네? 더 좋은 거 아닌가?
그런데 곧 의문이 생겼다.
메서드는 보통 내부 상태(필드)를 바꾸면서 동작하는데,
인터페이스는 추상 메서드는 있어도 멤버 필드(상태)는 못 가진다고 한다.
이거 좀 이상한데…?
abstract과 interface를 구분하는 기준은 “단일 상속 vs 다중 상속” 같은 문법 차이가 아니라, 상태(state)를 어떻게 다루는가에 있다.
1) “객체” vs “약속”
아래 문장 두 개로 정리하면 이해가 가장 빠르다.
- abstract class = 불완전한 객체(공통 상태 + 기본 동작 포함 가능)
- interface = 행동에 대한 계약(역할/능력만 표현)
즉, 추상 클래스는 “이런 종류의 객체다”라는 정체성(is-a)에 가깝고,
인터페이스는 “이런 행동을 할 수 있다”라는 역할(can-do)에 가깝다.
2) 진짜 차이: 상태(state)를 가질 수 있나?
| 구분 | abstract class | interface |
| 상태(필드) | ✅ 가능 | ❌ 불가(상수만) |
| 목적 | 공통 기반(템플릿) 제공 | 역할/규약 제공 |
| 관계 | is-a (정체성) | can-do (능력) |
| 다중 | ❌ 단일 상속 | ✅ 다중 구현 |
여기서 중요한 건 “interface는 필드를 못 가진다”는 규칙이 불편함이 아니라 의도된 설계라는 점이다.
3) interface가 상태를 못 갖는 이유: “다중 + 상태”는 충돌을 부른다
인터페이스가 다중 구현이 가능한데, 만약 상태까지 허용하면 이런 문제가 생긴다.
interface Flyable {
int speed;
}
interface Swimmable {
int speed;
}
class Duck implements Flyable, Swimmable { }
여기서 Duck.speed는 무엇을 의미해야 할까?
- Flyable의 speed?
- Swimmable의 speed?
- 둘 다면 어떻게 합칠까?
이런 애매함은 실제로 언어 설계에서 굉장히 위험하다.
그래서 Java는 결정을 내렸다.
인터페이스는 “행동의 계약”만 담당하게 하고,
공유 가능한 값(상수)만 허용하자.
그래서 인터페이스의 필드는 사실상 항상 상수다.
interface HttpStatus {
int OK = 200; // public static final
}
이건 “상태”가 아니라 “정의(값의 기준)”에 가깝다.
4) 그럼 interface의 메서드는 무엇으로 동작할까?
인터페이스 자체에는 상태가 없다.
대신 구현 클래스가 상태를 가지고, 인터페이스 메서드는 그 상태를 기반으로 동작한다.
interface Payable {
void pay(int amount);
}
class BankAccount implements Payable {
private int balance;
@Override
public void pay(int amount) {
balance -= amount;
}
}
- Payable은 “결제할 수 있다”는 규약만 제공
- 실제 데이터(balance)는 구현체가 관리
인터페이스가 “약속”이라는 말이 여기서 완성된다.
5) abstract class는 언제 유리할까?
추상 클래스는 공통 상태와 기본 동작을 공유하고 싶을 때 적합하다.
abstract class Animal {
protected int energy;
public void eat() {
energy += 10;
}
public abstract void move();
}
class Dog extends Animal {
@Override
public void move() {
energy -= 5;
}
}
- 모든 동물이 갖는 공통 상태(energy)
- 공통 동작(eat)
- 반드시 구현해야 하는 동작(move)
이런 구조는 인터페이스만으로 만들면 결국 중복이 늘어나기 쉽다.
6) 결국 “역할 분담”이다
비유로 설명하자면,
- abstract class: “이건 차량이다”(정체성/기반)
- interface: “이건 결제할 수 있다”(능력/역할)
그래서 실제 코드에서는 둘을 섞어 쓸 수도 있다.
abstract class Vehicle {
protected int speed;
public abstract void move();
}
interface Payable {
void pay(int amount);
}
class Taxi extends Vehicle implements Payable {
private int money;
@Override
public void move() {
speed += 10;
}
@Override
public void pay(int amount) {
money += amount;
}
}
Taxi는:
- Vehicle이라는 정체성을 가지면서(is-a)
- Payable이라는 역할도 수행한다(can-do)
7) 언제 무엇을 선택할까?
- 공통 상태(필드) + 기본 동작을 공유해야 한다 → abstract
- 서로 무관한 클래스들에 동일한 행동을 강제해야 한다 → interface
- “이 객체는 무엇인가?”가 중요하다 → abstract
- “이 객체는 무엇을 할 수 있는가?”가 중요하다 → interface
'Learning Log' 카테고리의 다른 글
| [멋사 클라우드 5기] Day 5 - Java 기본 라이브러리 & 컬렉션 정리 (0) | 2026.01.28 |
|---|---|
| equals가 있는데 hashCode는 왜 필요할까? (0) | 2026.01.27 |
| [멋사 클라우드 5기] Day 4 - 상속, 다형성, 그리고 abstract vs interface (0) | 2026.01.27 |
| [멋사 클라우드 5기] Day 3 - 객체 생성 흐름과 클래스 구조 이해하기 (1) | 2026.01.25 |
| [멋사 클라우드 5기] Day 2 - 배열, Git & GitHub 기본 개념 정리 (0) | 2026.01.25 |