13. 디폴트 메서드

주요내용
  • 디폴트 메서드란
  • 진화하는 API가 호환성을 유지하는 방법
  • 디폴트 메서드 활용 패턴
  • 해석 규칙

디폴트 메서드란#

인터페이스에 메서드를 추가하면서 발생하는 문제점#

  • 모든 인터페이스 구현체는 추가된 메서드를 구현해야 함
    • 이때 메서드를 구현하지 않더라도 바이너리 호환성은 유지됨 (미구현된 메서드를 호출만 하지 않으면 이상없음)
    • 대신, 인터페이스 구현체는 재빌드시 해당 메서드를 구현하지 않으면 에러를 발생 시킴
호환성
  • 바이너리 호환성: 뭔가를 바꾼 이후에도 에러 없이 기존 바이너리가 실행될 수 있는 상황
  • 소스 호환성: 코드를 고쳐도 기존 프로그램을 재컴파일할 수 있음
  • 동작 호환성: 코드를 바꾼 다음에도 같은 입력값에 같은 동작을 보장

디폴트 메서드 특징#

  • 호환성을 유지하면서 API를 바꿀 수 있도록 디폴트 메서드를 제공
  • 인터페이스의 메서드 앞에 default 를 붙임으로 구현이 가능해짐
  • 디폴트 메서드는 인터페이스 구현체에서 따로 구현하지 않아도 에러가 없음 (호환성 유지 가능)
Sized 인터페이스 예시
public interface Sized {
int size();
default boolean isEmpty() { // 디폴트 메서드
return size() == 0;
}
}
추상 클래스 vs 인터페이스
  • 클래스는 하나의 추상클래스만 상속받을 수 있음, 인터페이스는 여러 개 구현 가능
  • 추상 클래스는 인스턴스 변수(필드)를 가질 수 있음, 인터페이스는 불가

디폴트 메서드 활용 패턴#

선택형 메서드#

  • remove는 Iterator 구현체에 따라 선택적으로 지원했음
  • 이전에는 지원을 안해도 구현체에 하나하나 구현해줘야 했으나, 디폴트 메서드로 기본적으로 서포트 안하도록 구현가능
interface Iterator<T> {
...
default void remove() {
throw new UnsupportedOperationException();
}
}

다중 상속#

  • 이전에는 다중 상속하면 각각의 구현체에 대한 메서드를 다 구현해야 했지만, 이젠 기능 인터페이스 각각이 구현체를 가지고 있어 재사용성이 증가 됨
public class Monster implements Rotatable, Moveable, Resizable {
// 각 인터페이스의 디폴트 메서드는 미리 구현되어 있어 제공안해도 됨
}

해석 규칙#

문제코드
public interface A {
default void hello() {}
}
public interface B extends A {
default void hello() {} // 디폴트 메서드 재정의
}
public class C implements B, A {
public static void main(String... args) {
new C().hello(); // 어떤게 실행될까...
}
}

세 가지 해결 규칙#

  1. 클래스가 항상 이김
  2. 위에서 결정할 수 없다면, 서브 인터페이스가 이김
  3. 위에서 결졍할 수 없다면, 에러를 뱉음. 따라서 디폴트 메서드를 오버라이드하고 상위 메서드 선택

위의 상황에선 B의 hello가 출력 됨

다이아몬드 문제#

문제코드2
public interface A {
default void hello() {}
}
public interface B extends A {}
public interface C extends A {}
public class D implements B, C {
public static void main(String... args) {
new D().hello(); // 뭐가 출력?
}
}

메서드 선언은 하나 뿐이라, A의 hello가 선택됨

정리#

  • 인터페이스에 구현코드를 포함할 때는 디폴트 메서드, 정적 메서드를 정의할 수 있음
  • default 키워드로 메서드를 시작함
  • 기존 인터페이스에 메서드를 추가하면 소스 호환성이 깨짐
  • 호환성을 유지하려면 디폴트 메서드를 활용할 수 있음
  • 선택형 메서드와 동작 다중 상속에 디폴트 메서드 활용 가능
  • 공통된 디폴트 메서드 시그네쳐를 다중 상속해서 구현한다면 충돌이 발생, 다음과 같은 우선순위로 해결
    1. 클래스
    2. 서브 인터페이스
    3. 같은 레벨이라면 디폴트 메서드 오버라이드해서 선택
Last updated on