우아한테크코스 레벨 1에서 학습한 내용을 정리한 글입니다.
💭 들어가며
미션을 진행하면서 인터페이스와 추상 클래스의 특징을 명확히 이해하지 못한 채, 미션을 완료하기 위해 무작정 사용하곤 했다. 그런데 이번 장기 미션에서 페어였던 포포는 추상 클래스를 깔끔하게 잘 활용하는 반면, 그 차이를 온전히 따라가지 못하는 나를 보며 해당 개념을 다져야겠다고 생각했다. 이를 계기로 인터페이스와 추상 클래스, 그리고 일반 상속의 특징과 차이점 및 사용 시점 등에 대해 정리해 보았다.
✅ 인터페이스(Interface)
- interface 키워드로 선언된 구조이다.
- 기능을 정의하는 데 사용한다.
- 메서드 시그니처만을 가진다.
- 자바 8부터 default 메서드(구현 포함)와 static 메서드 선언이 가능해졌다.
- 기본적으로 모든 메서드가 추상 메서드로 선언된다.
- 다중 구현(Multiple Inheritance)이 가능하다. 즉, 한 클래스가 여러 인터페이스를 implements 할 수 있다.
- 일반적으로 public 메서드만 선언 가능하다.
🔽 예제 코드
public interface Flyable {
void fly();
}
public class Bird implements Flyable {
@Override
public void fly() {
System.out.println("새가 난다.");
}
}
참고: 마커 인터페이스
마커 인터페이스는 메서드가 전혀 없는 '빈 껍데기' 형태의 인터페이스이다. 쓸모없어 보일 수 있지만, 클래스가 특정 인터페이스(마커)를 구현했는지 여부를 통해 타입이나 의미를 표시할 수 있다. 추가로 공부해 보면 좋을 것 같다.
✅ 추상 클래스(Abstract Class)
- abstract 키워드로 선언된 클래스이다.
- extends 키워드를 사용하여 상속한다.
- 공통된 필드와 메서드를 가진 클래스들을 묶을 때 사용한다.
- 일부 메서드는 이미 구현되어 있을 수 있고, 일부는 abstract로 선언하여 하위 클래스에 구현을 강제할 수 있다.
- 객체 생성이 불가능하다.
- 다중 상속이 불가능하고, 단일 상속만 가능하다.
- 상태를 나타내는 필드(멤버 변수)를 포함할 수 있다.
🔽 예제 코드
public abstract class Animal {
protected String name;
// 일반 메서드
public String getName() {
return name;
}
// 추상 메서드
public abstract void sound();
}
public class Dog extends Animal {
public Dog(String name) {
this.name = name;
}
@Override
public void sound() {
System.out.println("왈왈!");
}
}
✅ 일반 상속(Inheritance)
- extends 키워드를 사용한다.
- 부모 클래스의 모든 필드와 메서드를 상속받는다.
- 다중 상속이 불가능하고, 단일 상속만 가능하다.
- 부모 클래스의 메서드를 오버라이딩(Override) 가능하다.
- 자식 클래스는 부모 클래스의 기능을 확장(extend)하는 개념이다.
🔽 예제 코드
public class Parent {
public void say() {
System.out.println("아침 밥은 무조건 먹어야 한다.");
}
}
public class Child extends Parent {
@Override
public void say() {
System.out.println("시간이 없어서 먹을 수가 없어요.");
}
}
✅ 차이점
인터페이스(Interface) | 추상 클래스(Abstract Class) | 일반 상속(Inheritance) | |
키워드 | interface | abstract class | class |
객체 생성 | X | X | O |
메서드 구현 | X (자바 8 이후 default 가능) | O (일부 가능) | O |
필드 (변수) | X (static final 상수만 가능) | O | O |
상속 관계 | implements (다중 구현 가능) | extends (단일 상속) | extends (단일 상속) |
다중 상속 | O | X | X |
자바 8 이후 인터페이스에도 default, static 메서드가 가능하지만, 인스턴스 필드(상태) 사용은 여전히 불가하므로 추상 클래스와는 구분된다.
✅ 언제 사용해야 할까?
🔽 인터페이스(Interface)
- 여러 클래스에서 공통 기능(행동)만 정의할 때
- 다중 구현이 필요할 때
- can-do 관계가 성립할 때 (Bird can Fly, Cat can Move)
🔽 추상 클래스(Abstract Class)
- 여러 클래스가 공통 속성과 동작(필드 + 메서드)을 공유할 때
- 일부 메서드는 공통 구현, 일부는 하위 클래스에서 구현해야 할 때
- 상속 구조는 필요한데, 인스턴스화는 불필요할 때
- is-a 관계가 성립할 때 (Dog is an Animal)
🔽 일반 상속(Inheritance)
- 부모 클래스의 모든 필드와 메서드를 재사용하고 싶을 때
- is-a 관계가 성립할 때 (Dog is an Animal)
인터페이스와 추상 클래스는 함께 조합되어 사용되기도 한다. 이는 추상 클래스의 중복 멤버 통합 기능과 인터페이스의 다중 상속 기능을 동시에 활용하기 위해서이며, 이러한 방식은 디자인 패턴에서도 자주 활용된다.
✅ 참고: default, static, final 키워드
▶ default
- 자바 8 이후, 인터페이스에서도 메서드 구현이 필요할 경우 사용할 수 있게 되었다.
- 원래는 인터페이스가 메서드 시그니처만 정의할 수 있었지만, default 키워드를 통해 인터페이스 내부에서도 구현 로직을 가질 수 있게 되었다.
- default 메서드는 인터페이스를 구현하는 클래스가 필요에 따라 오버라이딩할 수 있다.
🔽 예시 코드
interface Animal {
default void sound() {
System.out.println("소리를 낸다.");
}
}
▶ static
- 자바 8 이후 인터페이스에서도 static 메서드 선언이 가능하다.
- 클래스(혹은 인터페이스) 레벨에서 호출 가능한 메서드, 필드에 사용된다.
- 인스턴스 생성 없이 인터페이스명.메서드명() 형태로 호출한다.
- 구현 클래스에서 오버라이딩할 수 없다.
🔽 예시 코드
interface Animal {
static void info() {
System.out.println("Animal 인터페이스이다.");
}
}
▶ final
- 클래스, 메서드, 변수에 사용되며, 변경할 수 없도록 고정한다는 의미이다.
- 변수(필드)에서의 final: 재할당 불가, 상수로 취급
- 메서드에서의 final: 해당 메서드 오버라이딩 불가
- 클래스에서의 final: 해당 클래스 상속 불가
인터페이스에서는 사용할 수 없다.
🔽 예시 코드
- final class: 상속할 수 없는 클래스
final class Animal {
}
- final method: 오버라이딩 불가
abstract class Animal {
final void eat() {
System.out.println("먹는다.");
}
}
- final variable: 값 변경 불가
final int MAX = 10;
📍 참고 자료
'Programming > Java' 카테고리의 다른 글
[Java] Optional (0) | 2025.04.07 |
---|---|
[Java] 상속, 조합 (0) | 2025.04.01 |
[Java] 제네릭(Generic) (0) | 2025.03.17 |
[Java] 컬렉션 프레임워크(Collection Framework) (0) | 2025.03.11 |
[Java] 람다 표현식, 함수형 인터페이스, Stream API (0) | 2025.02.23 |