인터페이스와 클래스
- 인터페이스와 클래스는 자바의 핵심 개념
- 자바8에 람다와 함수형 프로그래밍이 추가되면서 인터페이스에 대한 변화가 발생
- 인터페이스에 대한 변화는 자바7에서 시작되었으며 자바8에서 대대적으로 변화됨
- 여기서는 다음과 같은 사항들에 대해 살펴봄
- 인터페이스의 문제점
- 인터페이스의 진화
- default 메서드
- 다중 상속
인터페이스 사용 시 문제점
- 인터페이스의 대표적인 문제점은 한번 배포되면 수정하기 어렵다는 점
- 이미 배포된 인터페이스에 새로운 기능(메서드)를 추가해서 배포한경우 다음과 같은 문제가 발생
- 해당 인터페이스를 구현한 모든 메서드에서 컴파일 에러 발생
- 구현한 클래스가 너무 많아 한번에 수정이 불가능
- 내부 뿐만 아니라 외부에서 해당 인터페이스를 사용하는 경우가 존재
- 클래스를 수정하지 않고 인터페이스를 컴파일 해서 배포하면 NoSuchMethod 에러 발생
- 추가되는 기능만 존재하는 인터페이스를 배포할 수 있지만 변경이 발생할때 마다 인터페이스를 계속 늘려나갈 수는 없음
- 자바의 컬렉션 프레임워크도 이러한 문제가 존재
- 컬렉션 프레임워크에서 가장 많이 사용되는 자료구조는 List, Map
- List의 상위 인터페이스는 Collection
- Collection은 최상위 인터페이스
- JDK11을 기준으로 Collection에는 1.2, 1.8, 9, 11에서 추가된 메서드가 존재
- 그 사이 버전에서는 추가가 안된것인가?
- 1.3,1.4, 5,6,7버전에서는 영향이 너무커 쉽게 추가할 수 없었음
- 만약 추가되어 컴파일에러나 NoSuchMethod가 발생하는 상황이 발생하면 개발자들은 다음과 같은 두 가지 경우에서 고려
- 전체 소스를 재컴파일하고 에러가나면 메서드 추가
- JDK를 업데이트 하지 않음 (대부분 이 방법을 선택)
- 이처럼 인터페이스에 변화를 주는것은 역효과를 발생시킬수 있음
- 자바 아키텍트들은 Collection에 대한 유틸리티인 Collections를 추가하여 여러가지 기능을 제공
- 자바7 까지는 collection에 sort가 없어 collections의 sort를 사용했지만 자바8 부터는 collection에서 제공하는 sort를 사용
인터페이스의 진화
인터페이스에 메서드를 추가하는것에 대한 문제점이 이렇게 심각하다면 자바8 부터는 어떻게 메서드를 추가할 수 있게 된것인지 알아봅니다.
- 자바 아키텍트들은 이러한 문제를 해결하기 위해 자바 8에서 인터페이스 기능을 대대적으로 변경
- 그 핵심은 디폴트(default) 메서드
자바 인터페이스의 발전과정
- 자바 1.1
- 상수 선언가능 - public static final로 인식
- 추상 메서드만 선언가능
- 자바 1.2
- 중첩 클래스 선언가능
- 중첩 인터페이스 선언가능
- 둘다 public static이어야 하며 생략가능
- 인터페이스 내부에 클래스는 내부클래스가 아닌 중첩(static 생략해도)클래스로 선언
- 자바 5
- 중첩 열거형 선언가능
- 중첩 어노테이션 선언가능
- 둘다 public static이어야 하며 생략할 수 있음
- 자바 8
- 실제 코드가 완성되어 있는 static 메서드 선언가능
- 실제 코드가 완성되어 있는 default 메서드 선언가능
- 둘다 public이며 생략가능
- 자바 9
- private 메서드 선언 가능
결론적으로 현재 인터페이스에는 총 9가지 항목을 선언가능
- 상수
- 추상 메서드
- 중첩 클래스
- 충첩 인터페이스
- 중첩 열거형
- 중첩 어노테이션
- static 메서드
- default 메서드
- private 메서드
default, static, private 메서드
- 인터페이스 내의 default, static, private메서드는 메서드 내용이 존재
- default 메서드는 메서드를 직접 구현하겠다고 컴파일러에게 알려주는 역할을 함
- static 메서드와 private메서드는 별도의 키워드 정의 없이 메서드의 명세를 선언하고 내용을 정의하면 됨
- static, private은 기존 인터페이스에 허용되지 않던 형태라 컴파일러가 혼란을 일으키지 않지만 default는 default라고 명시적으로 선언을 해주는 형태를 가짐
클래스와의 차이점과 제약 조건
- default메서드로 인해 추상클래스와 인터페이스의 차이점이 모호 해질수 있음
- 추상클래스와 인터페이스는 다음과 같은 차이를 가짐
- 추상클래스는 맴버 변수를 가질 수 있음, 인터페이스는 static 변수만 가질 수 있음
- 클래스는 오직 하나의 클래스만 상속할 수 있지만 인터페이스는 여러개를 상속받거나 구현가능
- default 메서드를 호출하고 싶을때는 다음과 같이 사용
- CustomInterface 선언된 getName이라는 default 메서드를 재정의
- 보통 상위 메서드에 접근하기 위해 super를 사용하지만 인터페이스의 default메서드는 다음과 같이 인터페이스 이름으로 호출
public class CustomClass implements CustomInterface {
// ...
@Override
public String getName() {
CustomInterface.super.getName();
}
}
다중 상속 관계
- 자바는 다중 상속을 지원하지 않음
- private 메서드는 상속되지 않음
- static 메서드는 인터페이스 또는 클래스 레벨로 정의되므로 메서드 오버라이드 범위에 속하지 않음
- default 메서드를 가진 여러개의 인터페이스를 구현할 경우 다중 상속의 효과를 얻게됨
- 이런 다중 상속으로 인해 다이야몬드 구조의 상속이 발생할 수 있음
- 상속받는 두개의 인터페이스에 같은 이름의 default 메서드가 존재하면 컴파일에러가 발생
- 이를 해결하기 위해 클래스에서 두개의 인터페이스에 동일한 이름으로 구현된 default 메서드와 같은이름의 메서드를 정의함(오버라이딩)으로써 해결가능
- 각 인터페이스에 존재하는 default 메서드는 위의 예제 코드와 같이 호출
- 만약 클래스를 상속받고 인터페이스를 구현하는데 동일한 이름의 메서드(인터페이스에는 default메서드)가 존재한다면 클래스의 메서드가 우선호출됨
인터페이스와 클래스 호출관계 3가지
- 클래스가 인터페이스에 대해 우선순위를 가짐
- 1번 관계를 제외하고 상속관계에 있을 경우 하위 클래스/인터페이스가 상위 클래스/인터페이스보다 우선순위를 가짐
- 위 두가지 경우를 제외하고 메서드 호출에 모호성이 존재할 경우 컴파일 에러가 발생할 수 있음