[도서][모던 자바 인 액션] - 디폴트 메서드

Junseo Kim·2021년 3월 15일
0

[모던 자바 인 액션]

목록 보기
11/13

기존에 존재하던 인터페이스에 새로운 메서드를 추가하면 인터페이스를 구현하는 모든 클래스에 메서드 구현을 해줘야한다. 이런 문제를 해결하기 위해 자바 8부터 정적 메서드 사용과 디폴트 메서드 를 사용할 수 있게 되었다. 메서드 구현을 포함하는 인터페이스를 정의할 수 있게 된 것이다. 이 결과 기존 코드에서 추가된 메서드 구현을 강요하지 않고 메서드를 추가할 수 있게 되었다.

List 인터페이스에 sort메서드는 디폴트 메서드이다.

default void sort(Comparator<? super E> c) {
    Collections.sort(this, c);
}

이런식으로 default 키워드가 붙어있는 메서드가 디폴트 메서드이다. 디폴트 메서드를 이용하면 자바 API의 호환성을 유지하면서 라이브러리를 바꿀 수 있다.

변화하는 API

라이브러리를 배포한 후 기능을 추가하면 어떤 문제가 발생할까? 자바 라이브러리 설계자가 라이브러리를 바꾸려고 할 때 문제가 발생한다.

만약 설계자가 라이브러리에 새로운 메서드를 추가했다면 해당 라이브러리 사용자는 어떤 문제를 겪게 될까?

1) 해당 인터페이스를 구현하는 모든 클래스는 새로 추가된 메서드를 구현해야한다. 하지만 사용자가 구현한 클래스는 새로 추가된 메서드를 구현하지 않고 있다.
인터페이스에 새로 메서드를 추가하면 바이너리 호환성(새로 추가된 메서드를 호출하지 않으면 새로운 메서드 구현 없이도 기존 클래스 파일 구현이 잘 동작한다.)은 유지된다. 하지만 언젠가 추가된 메서드를 사용하도록 코드가 바뀐다면 추가된 메서드가 구현되지 않은 클래스에서는 런타임에러가 발생한다.

2) 사용자가 전체 애플리케이션을 재빌드할 때 컴파일 에러가 발생한다.

즉, 공개된 API를 고치면 기존 버전과의 호환성 문제가 발생한다. 이런 문제를 디폴트 메서드를 이용해서 해결할 수 있다. 디폴트 메서드를 이용해서 API를 바꾸면 새롭게 바뀐 인터페이스에서 자동으로 기본 구현을 제공하므로 기존 코드를 고치지 않아도 된다.

디폴트 메서드란 무엇인가?

호환성을 유지하면서 API를 바꿀 수 있도록 추가된 기능이다. 인터페이스를 구현하는 클래스에서 구현하지 않은 메서드는 인터페이스 자체에서 기본으로 제공한다.

인터페이스에 존재하는 디폴트 메서드는 default라는 키워드와 함께 몸체까지 존재한다. 따라서 해당 인터페이스를 상속받는 구현체들은 디폴트메서드의 구현까지 상속을 받게되는 것이다. 따라서 소스 호환성이 유지된다.

추상 클래스와 인터페이스의 차이

둘 다 추상 메서드와 바디를 포함하는 메서드를 정의할 수 있다.
1) 클래스는 하나의 추상 클래스만 상속받을 수 있지만 인터페이스를 여러 개 구현할 수 있다.
2) 추상 클래스는 인스턴스 변수로 공통 상태를 가질 수 있지만 인터페이스는 인스턴스 변수를 가질 수 없다.

디폴트 메서드 활용 패턴

선택형 메서드

인터페이스를 구현하는 클래스에서 필요없는 메서드의 내용이 비어있는 상황을 본 적이 있을 수 있다.

디폴트 메서드를 이용하면 기본 구현을 제공할 수 있으므로 빈 구현을 제공하지 않아도되므로 필요없는 코드를 줄일 수 있다.

동작 다중 상속

디폴트 메서드를 이용하면 기존에는 불가능했던 동작 다중 상속도 구현할 수 있다. 자바 클래스는 하나의 클래스만 상속받을 수 있지만 인터페이스는 여러 개 구현할 수 있기 때문이다.

인터페이스에 디폴트 구현을 포함시키면 디폴트 메서드만 수정해줘도 모든 구현 클래스에서도 변경된 코드를 사용할수도 있다.(재정의 하지 않은 경우)

해석 규칙

인터페이스는 여러개를 상속받을 수 있기 때문에 같은 시그니처를 갖는 디폴트 메서드를 상속받는 상황이 생길 수 있다.

다른 클래스나 인터페이스로부터 같은 시그니처를 갖는 메서드를 상속받을 때는 세 가지 규칙을 따라야 한다.

1) 클래스가 항상 이긴다. 클래스나 슈퍼 클래스에서 정의한 메서드가 디폴트 메서드보다 우선권을 가진다.

2) 이외의 상황에서는 서브인터페이스가 이긴다. 상속관계를 갖는 인터페이스에서 같은 시그니처를 갖는 메서드를 정의할 때는 서브인터페이스가 이긴다.

3) 여전히 디폴트 메서드의 우선순위가 결정되지 않았다면 여러 인터페이스를 상속받는 클래스가 명시적으로 디폴트 메서드를 오버라이드하고 호출해야한다.

0개의 댓글