디폴트 메서드
- 전통적인 자바 인터페이스를 구현하는 클래스는 인터페이스의 모든 메서드 구현을 제공하거나 슈퍼 클래스의 구현을 상속받아야 한다.
- 인터페이스를 바꾸고 싶을 때 문제 발생 -> 모든 구현체를 다 고쳐야 함
- 자바 8 인터페이스의 변화
- 인터페이스 내부에 정적 메서드 사용
- 디폴트 메서드 기능 사용
- 즉 메서드 구현을 포함한 인터페이스를 정의할 수 있다.
- 기존 코드 구현을 바꾸지 않도록 하면서 인터페이스를 바꿀 수 있다.
- 결국 추상 클래스?
- 디폴트 메서드는 주로 라이브러리 설계자들이 사용한다.
- 정적 메서드와 인터페이스
- 보통 자바에서는 인터페이스와 인터페이스를 활용할 수 있는 정적 메서드를 정의하는 유틸리티 클래스를 활용한다. (Collection 인터페이스를 활용하는 Collections)
- 자바 8 이후에는 인터페이스에 정적 메서드를 사용함으로써 유틸리티 클래스가 필요가 없어졌지만 이전 버전과의 호환성을 유지할 수 있도록 자바 API에는 유틸리티 클래스가 남아있다.
13.1 변화하는 API
- 디폴트 메서드가 없을 때 인터페이스가 변경되면 발생되는 문제
- 라이브러리의 인터페이스에 새로운 메서드 추가
- 라이브러리 사용자가 라이브러리 인터페이스를 사용해 구현한 클래스는 바이너리 호환성 덕분에 새로운 메서드를 추가하지는 않아도 됨
- 하지만 언젠가 누군가가 인터페이스를 인수로 받아 새 메서드를 호출하고, 그 인터페이스 구현체가 새 메서드를 구현하지 않은 것이라면 런타임 에러가 발생한다.
- Exception in thread “main” java.lang.AbstractMethodError
- 새 메서드를 구현하지 않은 구현체를 포함하는 전체 애플리케이션을 재빌드할 때도 컴파일 에러가 발생한다.
- 공개 API를 고치면 기존 버전과의 호환성 문제가 발생한다. (때문에 자바 컬렉션 API 같은 기존 API는 고치기 어렵다)
- 바이너리 호환성, 소스 호환성, 동적 호환성
- 바이너리 호환성: 추가된 메서드를 호출하지만 않으면 새 메서드 구현 없이도 기존 클래스 파일 구현이 잘 동작함
- 소스 호환성: 코드를 고쳐도 기존 프로그램을 성공적으로 재컴파일할 수 있음을 의미한다.
- 동적 호환성: 코드를 바꾼 후에도 같은 입력 값이 주어지면 프로그램이 같은 동작을 실행한다는 의미다. (인터페이스에 메서드를 추가해도 호출할 일이 없는 경우)
13.2 디폴트 메서드란 무엇인가
- 자신을 구현하는 클래스에서 구현하지 않아도 되는 새로운 메서드 시그니처를 제공한다.
- 즉 디폴트 메서드를 추가하면 소스 호환성이 유지된다.
- 추상 클래스와 자바 8의 인터페이스
- 추상 클래스는 한 개만 상속 받을 수 있지만 인터페이스는 다중 상속이 가능하다.
- 추상 클래스는 인스턴스 변수로 공통 상태를 가질 수 있다. 하지만 인터페이스는 인스턴스 변수를 가질 수 없다.
13.3 디폴트 메서드 활용 패턴
- 디폴트 메서드를 이용하는 두 방식: 선택형 메서드와 다중 상속
- 선택형 메서드
- 인터페이스를 구현하는 클래스에서 잘 사용하지 않는 추상 메서드의 구현을 비워 놓는 것을 본 적 있을 것이다. (Iterator의 remove 메서드)
- 디폴트 메서드를 이용하면 인터페이스에서 구현이 가능하므로 빈 구현을 제공할 필요가 없다. (불필요한 코드 줄임)
- 동작 다중 상속
- 인터페이스는 다중 상속이 가능하다.
- ArrayList는 1개의 추상 클래스, 6개의 인터페이스를 상속한다.
- 예: 어떤 모양은 회전할 수 있고 움직일 수 있지만 크기는 조절하지 못한다.
- implements Rotatable, Movable (Resizable은 구현X)
- 옳지 못한 상속
- 1개의 메서드를 재사용하려고 100개의 메서드와 필드가 정의되어 있는 클래스를 상속받는 것은 좋은 생각이 아니다.
- 이럴 때는 델리게이션, 즉 멤버 변수를 이용해서 클래스에서 필요한 메서드를 직접 호출하는 메서드를 작성하는 것이 좋다.
- 인터페이스는 필요한 기능만 포함하도록 최소한으로 유지해야 한다. 재조립을 용이하게 하기 위해.
13.4 해석 규칙
- 인터페이스 다중 구현 중에 같은 시그니처의 디폴트 메서드를 같은 경우가 생길 수 있다.
- 실제로 자주 일어나지는 않지만 어떤 메서드가 실행될지 다음 세 규칙을 따른다.
- 클래스나 슈퍼 클래스에서 정의한 메서드가 디폴트 메서드보다 우선권을 갖는다.
- 클래스 다음으론 서브 인터페이스가 이긴다. 즉 인터페이스 B가 인터페이스 A를 상속한다면 B가 A를 이긴다.
- 위 두 규칙으로도 정해지지 않았다면 여러 인터페이스를 상속받는 클래스가 명시적으로 디폴트 메서드를 오버라이드하고 호출해야 한다.
'개발 서적 > 모던 자바 인 액션' 카테고리의 다른 글
[모던 자바 인 액션] Chapter11. Null 대신 Optional 클래스 (0) | 2022.03.28 |
---|---|
[모던 자바 인 액션] Chapter7. 병렬 데이터 처리와 성능 (0) | 2022.03.02 |
[모던 자바 인 액션] Chapter4. 스트림 소개 (0) | 2022.02.28 |