Back_End/JAVA

자바(JAVA)의 Default Interface란?

10Biliion 2025. 2. 28. 15:00

 

 

 

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("전기차가 조용히 시동을 겁니다.");
    }
}

위 코드에서 ElectricCarstart() 메서드를 직접 구현하여 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");
    }
}

위 코드에서는 AB 두 인터페이스에서 동일한 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로 제공할 수 없음