1️⃣ 인터페이스는 “상속”이라기보단 “규약(약속)”
자바에서 interface는 일종의 ‘설명서’ 혹은 ‘계약서’입니다.
즉,
“이 인터페이스를 구현하는 클래스는
여기에 적힌 메서드를 반드시 만들어야 한다.”
라는 규칙(Contract) 을 강제하는 역할이에요.
📘 예시
// 인터페이스 (약속서)
public interface Animal {
void sound(); // 몸체가 없는 메서드 (규칙만 정의)
}
// 구현 클래스
public class Dog implements Animal {
@Override
public void sound() {
System.out.println("멍멍!");
}
}
이 구조는 ‘상속’보다는 ‘구현(implementation)’이에요.
👉 extends는 상속,
👉 implements는 인터페이스 구현.
🧩 2️⃣ “상속”과 “인터페이스 구현”의 차이
구분 상속 (extends) 인터페이스 (implements)
| 관계 | 부모 → 자식 (기능을 물려받음) | 규칙을 따름 (형태만 구현) |
| 키워드 | extends | implements |
| 메서드 | 부모의 메서드를 그대로 상속 가능 | 반드시 인터페이스의 메서드를 구현해야 함 |
| 다중 가능 여부 | ❌ 단일 상속만 가능 | ✅ 여러 인터페이스 구현 가능 |
| 목적 | 코드 재사용 | 공통 규약 강제 |
📘 예시로 비교
클래스 상속
class Parent {
void hello() { System.out.println("Hello from Parent"); }
}
class Child extends Parent {
void bye() { System.out.println("Bye from Child"); }
}
➡️ Child는 Parent의 기능을 “물려받음”
인터페이스 구현
interface Flyable {
void fly(); // 구현해야 함
}
class Bird implements Flyable {
public void fly() { System.out.println("새가 납니다"); }
}
➡️ Bird는 Flyable의 규칙을 “이행함”
⚙️ 3️⃣ 인터페이스는 다중 “구현” 가능
자바는 클래스는 하나만 상속 가능하지만,
인터페이스는 여러 개 구현 가능해요 👇
interface Flyable { void fly(); }
interface Swimmable { void swim(); }
class Duck implements Flyable, Swimmable {
public void fly() { System.out.println("날아오른다!"); }
public void swim() { System.out.println("헤엄친다!"); }
}
➡️ 이런 다중 행동 정의가 인터페이스의 큰 장점
4️⃣ 정리하자면
항목 클래스 상속 인터페이스
| 키워드 | extends | implements |
| 관계 | 부모 → 자식 | 규약 → 구현체 |
| 목적 | 코드 재사용 | 기능 약속 |
| 메서드 구현 | 선택적(Override 가능) | 필수(Override 해야 함) |
| 다중 적용 | 불가능 | 가능 |
| 실제 표현 | “is-a 관계” | “can-do 관계” |
✅ 한 줄 요약
🔸 인터페이스는 “상속”이 아니라 “규약(약속)”을 구현(implements) 하는 구조
🔸 클래스 상속(extends)은 부모의 기능을 물려받는 것,
인터페이스 구현(implements)은 정해진 형식을 따라가는 것.
인터페이스의 메서드는 “반드시 오버라이드해야 하지만”, @Override 키워드는 선택사항
1️⃣ 인터페이스의 메서드는 “무조건 구현”해야 함
인터페이스 안의 메서드는 기본적으로 전부 abstract(추상 메서드)
즉, 구현이 없고, 형태만 있다
public interface Animal {
void sound(); // 구현(몸체) 없음
}
이걸 구현(implements)하는 클래스는 반드시 sound()를 만들어야 한다.
public class Dog implements Animal {
public void sound() { // ✅ 오버라이드 필요
System.out.println("멍멍!");
}
}
만약 구현 안 하면 이렇게 에러 👇
❌ Class 'Dog' must either be declared abstract or implement abstract method 'sound()' in 'Animal'
2️⃣ @Override는 “붙이는 게 원칙이지만, 필수는 아님”
@Override는 단지 “이 메서드는 부모(또는 인터페이스)의 메서드를 재정의한 것”
라고 컴파일러에 알려주는 표시용 어노테이션
public class Dog implements Animal {
@Override // 권장 👍
public void sound() {
System.out.println("멍멍!");
}
}
위처럼 써야:
- 메서드 이름/시그니처가 잘못되면 컴파일 에러로 알려줌
- 실수(예: 오타) 방지
안 써도 실행은 됩니다 👇
public class Dog implements Animal {
public void sound() { // @Override 없어도 동작은 함
System.out.println("멍멍!");
}
}
3️⃣ 실무에서는 “항상 붙인다”가 표준
이유 설명
| ✅ 컴파일러 체크 기능 | 부모 인터페이스에 진짜 메서드가 있는지 확인 |
| ✅ 코드 가독성 향상 | 협업 시, 재정의된 메서드라는 걸 한눈에 파악 |
| ✅ 유지보수 용이 | 리팩토링 시 안전하게 추적 가능 |
🔸 그래서 실무에서는 “인터페이스든, 상속이든, 오버라이드할 땐 무조건 @Override 붙이는 게 기본 습관”이에요.
💡 요약 정리
구분 의미 필수 여부
| 인터페이스 메서드 구현 | 반드시 구현해야 함 | ✅ 필수 |
| @Override 어노테이션 | “이 메서드는 부모의 메서드 재정의임” | ⚙️ 선택 (하지만 권장) |
✅ 한 줄 정리
인터페이스의 메서드는 무조건 “오버라이드해서 구현”해야 하고,
@Override는 “붙이는 게 원칙이지만 없어도 돌아는 간다.”
원하면 “인터페이스 오버라이드 vs 상속 오버라이드”를
실행 순서까지 보여주는 간단한 예제로 정리해줄까?
(예: 부모 → 인터페이스 → 자식 클래스 순으로 호출 흐름)
'JAVA' 카테고리의 다른 글
| 쿼리 DSL 메서드 종류 (0) | 2025.11.13 |
|---|---|
| abstract 추상 클래스 or 추상 메서드 (0) | 2025.11.12 |
| Logger , LoggerFactory 를 사용하는 이유 (0) | 2025.11.12 |
| @Configuration 과 xml 과 yml 설정 파일의 차이 (1) | 2025.11.12 |
| @SuppressWarnings 어노테이션 (0) | 2025.11.12 |