13. 디폴트 메서드
주요내용
- 디폴트 메서드란
- 진화하는 API가 호환성을 유지하는 방법
- 디폴트 메서드 활용 패턴
- 해석 규칙
#
디폴트 메서드란#
인터페이스에 메서드를 추가하면서 발생하는 문제점- 모든 인터페이스 구현체는 추가된 메서드를 구현해야 함
- 이때 메서드를 구현하지 않더라도 바이너리 호환성은 유지됨 (미구현된 메서드를 호출만 하지 않으면 이상없음)
- 대신, 인터페이스 구현체는 재빌드시 해당 메서드를 구현하지 않으면 에러를 발생 시킴
호환성
- 바이너리 호환성: 뭔가를 바꾼 이후에도 에러 없이 기존 바이너리가 실행될 수 있는 상황
- 소스 호환성: 코드를 고쳐도 기존 프로그램을 재컴파일할 수 있음
- 동작 호환성: 코드를 바꾼 다음에도 같은 입력값에 같은 동작을 보장
#
디폴트 메서드 특징- 호환성을 유지하면서 API를 바꿀 수 있도록 디폴트 메서드를 제공
- 인터페이스의 메서드 앞에
default
를 붙임으로 구현이 가능해짐 - 디폴트 메서드는 인터페이스 구현체에서 따로 구현하지 않아도 에러가 없음 (호환성 유지 가능)
Sized 인터페이스 예시
추상 클래스 vs 인터페이스
- 클래스는 하나의 추상클래스만 상속받을 수 있음, 인터페이스는 여러 개 구현 가능
- 추상 클래스는 인스턴스 변수(필드)를 가질 수 있음, 인터페이스는 불가
#
디폴트 메서드 활용 패턴#
선택형 메서드- remove는 Iterator 구현체에 따라 선택적으로 지원했음
- 이전에는 지원을 안해도 구현체에 하나하나 구현해줘야 했으나, 디폴트 메서드로 기본적으로 서포트 안하도록 구현가능
#
다중 상속- 이전에는 다중 상속하면 각각의 구현체에 대한 메서드를 다 구현해야 했지만, 이젠 기능 인터페이스 각각이 구현체를 가지고 있어 재사용성이 증가 됨
#
해석 규칙문제코드
#
세 가지 해결 규칙- 클래스가 항상 이김
- 위에서 결정할 수 없다면, 서브 인터페이스가 이김
- 위에서 결졍할 수 없다면, 에러를 뱉음. 따라서 디폴트 메서드를 오버라이드하고 상위 메서드 선택
위의 상황에선 B의 hello가 출력 됨
#
다이아몬드 문제문제코드2
메서드 선언은 하나 뿐이라, A의 hello가 선택됨
#
정리- 인터페이스에 구현코드를 포함할 때는 디폴트 메서드, 정적 메서드를 정의할 수 있음
default
키워드로 메서드를 시작함- 기존 인터페이스에 메서드를 추가하면 소스 호환성이 깨짐
- 호환성을 유지하려면 디폴트 메서드를 활용할 수 있음
- 선택형 메서드와 동작 다중 상속에 디폴트 메서드 활용 가능
- 공통된 디폴트 메서드 시그네쳐를 다중 상속해서 구현한다면 충돌이 발생, 다음과 같은 우선순위로 해결
- 클래스
- 서브 인터페이스
- 같은 레벨이라면 디폴트 메서드 오버라이드해서 선택