인터페이스는 자바의 발전에 빼먹으면 안될 중요한 녀석이다. 이러한 인터페이스는 점점 발전하고 자바 8에 이르러 신기한 기능이 추가 되었다. 이를 통하여 개발자들은 호환성을 유지하며 더 좋은 품질의 라이브러리를 개발한다거나 현 시스템에 좋은 기능을 추가 할 수 있었다. 이러한 기능을 하는 인터페이스의 디폴트 메서드를 알아 볼 것이다.
1.
디폴트 메서드란 무엇인가?
2.
진화하는 API가 호환성을 유지하는 방법
3.
디폴트 메서드의 활용 패턴
4.
해결 규칙
디폴트 메서드란 무엇인가?
인터페이스를 구현하는 클래스는 인터페이스에서 정의하는 모든 메서드 구현을 제공하거나 아니면 슈퍼클래스의 구현을 상속받아야한다. 이는 다시 말하면 인터페이스를 상속받는 구현해야하는 의무를 지닌 클래스는 인터페이스 내부에 정의된 모든 메서드를 구현해야한다. 이렇게 된다면 무슨일이 벌어질까? 예를 들어 내가 sort()라는 메서드를 인터페이스 내부에 정의하는 것을 까먹고 라이브러리를 출시했다. 차후 이를 알게 된 나는 모든 자료구조에 대한 sort를 다시 재정의해줘야한다. 이렇듯 나는 많이 당황스러울 것이다. 하지만 이를 해결하고자 새로운 기능이 자바 8에 추가 되었다. 기본 구현을 포함하는 인터페이스 정의방법을 두가지로 나누어 제공한다. 하나는 인터페이스 내부에 정적 메서드를 사용하는 것과 두번째로 인터페이스의 기본 구현을 제공할 수 있도록 디폴트 메서드 기능을 사용하는 것이다. 결과적으로 기존 인터페이스를 구현하는 클래스는 자동으로 인터페이스의 디폴트 메서드를 상속받게 되고 이를 구현해야하는 의무를 덜 수 있다.
Collection의 stream()
public interface Collection<E> extends Iterable<E> {
...
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
}
numberList.stream() // List Interface 에는 stream 메서드가 없다. 하지만 사용할 수 있다.
Java
복사
디폴트 메서드의 장점은 무엇인가? (필자의 생각)
•
호환성 유지 : 인터페이스만 고치면 문제를 해결할 수 있다. 그 말인 즉, 다른 구현 코드를 돌아보지 않아도 된다는 말이다. 그럼 다른 구현코드를 사용하는 코드들에 영향을 주는 빈도가 적어질 것이다.
•
구현 클래스의 수정 없음 : 기존 클래스를 고치는 것이 아니다. 인터페이스만 고치면 된다.
•
유틸 클래스의 제거 : 기존에 정적 유틸클래스를 만들어 조작하는 일을 많이 했다. 왜냐하면 자주사용해야하는데 모든 코드에 유틸적인? 행위를 하는 메서드를 다 정의해주기 힘들었기 때문이다. 하지만 이제는 인터페이스에 하나만 정의할 수 있기 때문에 유틸클래스를 제거할 수 있다,
진화하는 API가 호환성을 유지하는 방법
추상 클래스와 인터페이스?
추상 클래스와 인터페이스는 뭐가 다를까? 둘다 추상 메서드와 바디를 포함하는 메서드를 정의할 수 있는데 말이다.
1. 클래스는 하나의 추상 클래스만 상속받을 수 있지만 인터페이스는 여러 개 구현할 수 있다.
2. 추상 클래스는 인스턴스 변수로 공통 상태를 가질 수 있다. 하지만 인터페이스는 변수를 가질 수 없다.
디폴트 메서드의 활용 패턴
디폴트 메서드를 활용하면 API 또는 프로그램 자체의 호환성을 유지할 수 있음을 확인했다. 그렇다면 좀 더 디폴트 메서드를 활용하는 방법을 알아볼 차례이다. 여기서는 선택형 메서드와 동작 다중 상속을 설명한다.
옳지 못한 상속?
상속으로 코드를 재사용하는 것으로 모든 문제를 해결할 수 있는 것은 아니다. 예를 들어 한 개의 메서드를 재사용하려고 100개의 메서드와 필드가 정의된 클래스를 상속받는 것은 좋은 생각이 아니다. 이럴 때는 델리게이션, 즉 멤버변수를 이용하여 클래스에서 필요한 메서드를 직접 호출하는 메서드를 작성하는 것이 좋다.
해결 규칙
자바의 클래스는 하나의 부모 클래스만 상속받을 수 있지만 여러 인터페이스를 동시에 구현할 수 있다. 자바 8에는 디폴트 메서드가 추가되었으므로 같은 시그니처를 갖는 디폴트 메서드를 상속받는 상황이 생길 수 잇다. 이런 상황에서는 어떤 인터페이스의 디폴트 메서드를 사용하는 것일까?
1.
클래스가 항상 이긴다. 클래스나 슈퍼클래스에서 정의한 메서드가 디폴트 메서드 보다 항상 우선권을 가진다.
2.
1번 규칙 이외의 상황(클래스, 슈퍼클래스가 없는 상황)에서는 서브 인터페이스가 이긴다. 상속관계를 갖는 인터페이스에서 같은 시그니처를 갖는 메서드를 정의할 때는 서브인터페이스가 이긴다.
3.
여전히 디폴트 메서드의 우선순위가 결정되지 않았다면 여러 인터페이스를 상속받는 클래스가 명시적으로 디폴트 메서드를 오버라이드하고 호출해야한다.
몇 가지 상황들
결론
•
자바 8의 인터페이스는 구현 코드를 포함하는 디폴트 메서드, 정적 메서드를 정의할 수 있다.
•
디폴트 메서드의 정의는 default 키워드로 시작하며 일반 클래스 메서드처럼 바디를 갖는다.
•
공개된 인터페이스에 추상 메서드를 추가하면 소스 호환성이 깨진다.
•
디폴트 메서드 덕분에 호환성유지가 가능해졌다.
•
해석규칙이라는 상속 충돌 문제를 해결하는 방법이 있다.