
Java 8부터 인터페이스에 default 메서드를 정의할 수 있는 기능이 추가되었습니다. 기존에는 인터페이스가 오직 메서드의 시그니처만 정의하고, 실제 구현은 해당 인터페이스를 구현하는 클래스에서 제공해야 했습니다. 그러나 default 메서드를 사용하면 인터페이스에서도 기본적인 메서드를 구현할 수 있습니다.
1. Default 메서드란?
default 메서드는 인터페이스에서 메서드의 기본 구현을 제공하는 기능입니다. default 키워드를 사용하여 선언하며, 이를 구현하는 클래스는 해당 메서드를 별도로 재정의하지 않아도 사용할 수 있습니다.
기본 문법
interface MyInterface {
default void sayHello() {
System.out.println("Hello from MyInterface");
}
}
위 코드에서 sayHello 메서드는 기본적으로 "Hello from MyInterface"를 출력하도록 구현되어 있습니다.
2. Default 메서드가 필요한 이유
(1) 인터페이스 확장 시 하위 호환성 유지
Java 8 이전에는 인터페이스에 새로운 메서드를 추가하면 기존의 모든 구현 클래스들이 해당 메서드를 반드시 구현해야 했습니다. 하지만 default 메서드를 활용하면 기존 코드를 수정하지 않고도 인터페이스에 새로운 기능을 추가할 수 있습니다.
interface Printer {
void print(String message);
default void printWithTimestamp(String message) {
System.out.println(System.currentTimeMillis() + ": " + message);
}
}
위 인터페이스에서 printWithTimestamp라는 메서드가 추가되었습니다. 기존에 Printer를 구현한 클래스들은 이 메서드를 구현하지 않아도 기본 구현을 사용할 수 있습니다.
(2) 코드 중복 방지 및 재사용성 증가
default 메서드를 사용하면 여러 구현 클래스에서 공통적으로 필요한 기능을 인터페이스에서 직접 제공할 수 있어, 코드 중복을 줄일 수 있습니다.
3. Default 메서드 사용 예제
(1) 기본적인 default 메서드 사용
interface Vehicle {
default void start() {
System.out.println("차량이 시동을 겁니다.");
}
}
class Car implements Vehicle {
// 별도의 구현 없이 Vehicle 인터페이스의 기본 메서드 사용 가능
}
public class Main {
public static void main(String[] args) {
Car myCar = new Car();
myCar.start(); // "차량이 시동을 겁니다." 출력
}
}
(2) Default 메서드 오버라이딩
클래스에서 default 메서드를 재정의할 수도 있습니다.
class ElectricCar implements Vehicle {
@Override
public void start() {
System.out.println("전기차가 조용히 시동을 겁니다.");
}
}
위 코드에서 ElectricCar는 start() 메서드를 직접 구현하여 Vehicle의 기본 구현을 덮어씌웠습니다.
4. 다중 인터페이스 충돌 문제
Java는 다중 상속을 지원하지 않지만, 두 개 이상의 인터페이스에서 같은 시그니처의 default 메서드를 제공할 경우 충돌이 발생할 수 있습니다.
(1) 충돌 예제
interface A {
default void hello() {
System.out.println("Hello from A");
}
}
interface B {
default void hello() {
System.out.println("Hello from B");
}
}
class C implements A, B {
@Override
public void hello() {
System.out.println("Hello from C");
}
}
위 코드에서는 A와 B 두 인터페이스에서 동일한 hello() 메서드를 제공하고 있어 C 클래스에서 반드시 오버라이딩해야 합니다.
public class Main {
public static void main(String[] args) {
C obj = new C();
obj.hello(); // "Hello from C" 출력
}
}
만약 C에서 hello()를 오버라이딩하지 않으면 컴파일 오류가 발생합니다.
5. Default 메서드와 Object 클래스
인터페이스에서 equals(), hashCode(), toString()과 같은 Object의 기본 메서드를 default로 제공할 수 없습니다. 이는 모든 클래스가 이미 Object를 상속받기 때문에 인터페이스에서 Object의 메서드를 오버라이딩할 경우 충돌이 발생할 수 있기 때문입니다.
예를 들어, 아래 코드는 컴파일 오류를 발생시킵니다.
interface InvalidInterface {
default boolean equals(Object obj) { // 오류 발생
return true;
}
}
6. Default 메서드와 정적 메서드의 차이점
Java 8에서는 인터페이스에 static 메서드도 추가할 수 있습니다. 하지만 static 메서드는 인스턴스가 아닌 인터페이스 자체에서 호출됩니다.
interface Util {
static void log(String message) {
System.out.println("Log: " + message);
}
}
public class Main {
public static void main(String[] args) {
Util.log("Hello World"); // "Log: Hello World" 출력
}
}
반면, default 메서드는 인스턴스에서 호출됩니다.

default 메서드는 기존 인터페이스의 기능을 확장하면서도 하위 호환성을 유지할 수 있습니다. 코드 중복을 줄이고, 유지보수성을 높일 수 있습니다. 하지만 다중 인터페이스를 구현할 때는 충돌 문제가 발생할 수 있으므로 주의해야 합니다.
정리:
- default 메서드는 인터페이스에서 기본 구현을 제공할 때 사용
- 기존 인터페이스를 변경해도 하위 호환성을 유지 가능
- 다중 인터페이스 충돌 시 반드시 재정의 필요
- Object의 기본 메서드는 default로 제공할 수 없음
'Back_End > JAVA' 카테고리의 다른 글
자바(JAVA) Arrays.sort() vs Collections.sort() (0) | 2025.03.11 |
---|---|
자바(JAVA) DAO, DTO, VO 란? (0) | 2025.02.26 |
자바(JAVA) Synchronized (0) | 2025.02.24 |
자바(Java) Optional 이란? (0) | 2025.02.14 |
얼리 리턴 패턴(Early Return Pattern) 이란? (0) | 2025.02.14 |