인터페이스 특징(자바 8 이후)
-> 인스턴스를 생성할 수 없고 상수나 추상메서드를 가질 수 있다.
-> 메서드 body가 없는 추상 메서드를 가진다.
-> 디폴트 메소드, static 메서드만 가질 수 있다(JDK 1.8이상)
디폴트 메서드 : 인터페이스에서 body를 가지는 메서드(반드시 오버라이드 할 필요는 없음. 접근 제어자는 public)
-> 이미 작성된 인터페이스에서 기능을 추가하려고 할 때 디폴트 메서드 없이는 구현체 클래스들이 전부 오버라이드를 해야하지만, 디폴트 메서드가 있다면 오버라이드 작업 불필요
디폴트 메서드로 추상 클래스와 비슷한 것 같으나, 인터페이스는 다중 상속이 가능하다는 차이점이 있음
다중 상속 없이 추상클래스만으로 표현하려면 2^n -1개의 클래스가 필요함
-> 인터페이스를 사용하면 조합적 폭발을 방지할 수 있음
다이아몬드 문제 : 다중 상속 시 부모 클래스에 같은 시그니처의 메서드가 있을 때 어떤 메서드를 상속받아야 하는지 판별할 수 없는 문제
-> 인터페이스 다중 상속(추상 메서드는 구체적 선언부(body))가 없기 때문에 모호함이 발생하지 않음
-> 인터페이스 다중 상속 시, 공통 조상을 갖지 않는 두 클래스에 관계를 맺을 수 있음
--> 사용자 입장에서는 내부적 구저에 대한 이해 없이 약속된 행위 보장
-> 추상 클래스도 가능하나 상속 관계에 있는 클래스 끼리만 가능함(인터페이스가 좀 더 유연하게 다형성 적용 가능)
추상클래스 사용 경우
1) 굉장히 밀접하게 관련된 클래스끼리 코드를 공유해야 할 때
2) 추상클래스의 하위 구현체 클래스들이 공통된 필드나 메서드를 많이 공유하고, 접근제어자가 public이 아닌 경우
3) Non-static 혹은 non-final의 필드로 객체의 상태를 바꿔야 하는 경우
인터페이스 사용 경우
1) 관련이 없는 클래스들끼리 관계를 맺어줄 때
2) 특정 데이터 타입의 동작을 지정하려고 하지만 해당 동작을 누가 구현하는지는 중요하지 않을 때
3) 다중 상속이 필요한 때
Skeletal Implementation(추상 클래스, 인터페이스 동시 사용)
-> 중복되는 메서드를 공통으로 갖는 추상클래스로 구현
-> 바디가 다른 메서드만 하위 클래스에서 추상클래스 상속받아서 구현(중복 코드 사라짐 -> 코드량 감소)
-> ex) Java Collection의 AbstractList, AbstractMap 등
인터페이스 디펄트 메서드가 있는데?
-> 인터페이스 디펄트 메서드의 접근 제어자는 public이기 때문에 내부 메서드를 클라이언트가 조작하거나 알 수 있기 때문
-> 숨기고 싶은 메서드가 있다면 추상클래스의 private나 protected를 활용하여 숨기기 가능
-> 디폴트 메서드에서는 하위 구현체 클래스에 대한 상태(필드에 대한 참조 불가)\
디폴트 메서드의 원인 : 이미 존재하는 인터페이스의 하위호환 목적 -> 새로 인터페이스를 만드는 시점에서 디폴트 메서드를 사용하면 도입 취지와 맞지 않음
자바8 이전 인터페이스는 추상 클래스 말고는 어떠한 클래스들도 가질 수 없었음
구현체 입장에서는 인터페이스에 추가된 기능이 기존의 기능과 충돌이 없으리란 보장이 없음
ex) removeIf(조건 맞는거 삭졔)
멀티쓰레드 환경의 SynchronizedCollection에서는 Runtime Error 맞이할 수있음 -> lock을 통해 해결, 즉 default 메서드를 목적에 맞게 재정의하면 해결 가능(오버라이드)
디폴트 메서드 다중 상속 시 약간의 우선순위로 해결
1) 구현하는 클래스나 슈퍼클래스가 우선권을 먼저 가진다
2) 상속받는 인터페이스
3) 명시적 사용(어떤 메서드를 출력할건지 결정)
디폴트 메서드는 런타임 오류를 일으킬 수 있다
이미 구현된 인터페이스에 디폴트 메서드를 추가하는 것은 신중히 해야한다.
디폴트 메서드를 추가하려면 릴리즈 전에 반드시 테스트를 거쳐야 한다.