자바가 제공하는 다중 구현 메커니즘은 interface 와 abstract class 가 있음.
그럼 일단 interface 와 abstract class 가 뭔지 알아보자
다중 상속을 진행한다고 했을때 어떤 함수를 사용한다고 했을 때 어떤 부모의 함수를 가져다가 쓸지 몰라서 안됨.
다중상속이 안되는 이유
다중 구현은 가능
-> 근데그럼 다중구현을 할때 같은 함수를 override 한다고치면..? 껍데기만 있어서 가능?
이제(자바 8버전 이상?)는 두 메커니즘 모두 인스턴스 메서드를 구현형태로 제공할 수 있다.
반드시 객체 생성해야만 호출 가능한 메서드
반대개념은 클래스 메서드로 메서드 앞에 static
키워드가 붙어있으면 클래스 메서드이다.
interface를 구현하는건 그냥 interface가 구현하라고 요구하는 메서드만 추가하고 implements
절만 추가하면 된다. Java 플랫폼에서도 Comparable
, Iterable
, AutoClosable
인터페이스가 새로 추가되었을 때 표준 라이브러리의 수많은 기존 클래스가 이 인터페이스를 구현한 채 릴리스 되었었다.
이에 비해 Comparable
같은 interface를 abstract class 로 구현했다고 생각해보면, 수많은 클래스들이 공통 조상을 가지게 되지만, 또 다른 iterable
같은 기능을 추가하고 싶을때 이 또한 공통 조상이어야 하므로 불가능한 계층구조를 요구하게 된다.
클래스가 구현할 수 있는 타입으로, 믹스인을 구현한 클래스에 원래의 주된타입 외에도 특정 선택적 행위를 제공한다고 선언하는 효과..?
뭔소린지 모르겠다. 구글링을 해보았다.
객체지향 프로그래밍 언어에서 mix-in은 다른 클래스의 부모 클래스가 되지 않으면서 다른 클래스에서 사용할 수 있는 메서드를 포함한 클래스를 뜻한다.
상속이 가지는 is-a 관계와 대척되는 has-a 관계를 칭하는 말 같다. Interface는 해당 interface를 구현하는 클래스에게 어떤 클래스인지를 알려주기 보다는 어떤 기능을 가지고 있는지를 명시하기 때문에 has-a 관계라고 할 수 있다.
타입을 계층적으로 정의하면 수많은 개념을 구조적으로 잘 표현할 수 있지만, 현실에서는 계층을 엄격히 구분하기 힘든 개념도 있다.
public interface Singer {
AudioClip sing(Song s);
}
public interface Songwriter {
Song compose(int chartPosition);
}
public interface SingerSongwriter extends Singer, Songwriter{
AudioClip strum();
void actSensitive();
}
인터페이스는 기능에 대한 선언만 가능하기 때문에, 실제 코드를 구현한 로직은 포함될 수 없었지만, 자바 8부터 default method가 나오며 이 법칙이 깨졌다.
interface MyInterface {
default void printHello() {
System.out.println("Hello World");
}
}
이런 식으로 사용할 수 있다.
이런 기능은 interface의 메서드 중 구현 방법이 명백한 것이 있으면 default method으로 제공하여 프로그래머들의 일감을 덜어 줄 수 있다.
equals
hashCode
같은 Object의 메서드는 default method으로 제공하면 안된다.인터페이스와 추상골격구현클래스를 함께 제공하는 식으로 인터페이스와 추상 클래스의 장점을 모두 취하는 방법도 있다.
interface로는 타입을 정의하고, 필요하면 default 메서드도 몇개 구현, 그리고 나머지 메서드는 추상골격클래스로 구현하는 방법으로 interface를 구현하는 방식을 템플릿 메서드 패턴 이라고 한다.
골격 구현 클래스의 좋은 예시들로는 collection 프레임워크의 AbstractCollection
AbstractSet
AbstractList
등이 있다.
무엇보다 abstract class처럼 구현을 도와주는 동시에 abstract class 로 정의할때 따라오는 심각한 제약에서 자유롭다ㅡㄴㄴ 점이다.
간단한 예로 Map.Entry
인터페이스를 살펴보자.
Map.Entry 사용예시
한줄로 요약하자면 프로그래밍할때 자주 사용하는 map 자료구조의 iteration 작업의 최적화를 위해 나온 interface 라고 할 수 있다.
public abstract class AbstractMapEntry<K,V>
implements Map.Entry<K,V> {
@Override public V setValue(V value){
//구현
}
@Override public boolean equals(Object O){
//구현
}
@Override public int hashCode(){
//구현
}
@Override public String toString(){
return getKey() + "=" + getValue();
}
}
골격 구현은 기본적으로 상속해서 사용하는걸 가정하므로 설계 및 문서화 지침까지 모두 따라야 한다.
Abstract Class 보다는 Interface 를 사용하자.