아이템 51에서 매개변수 타입으로 클래스가 아닌 인터페이스를 사용하라고 했다. 이 조언을 객체는 클래스가 아닌 인터페이스로 참조하라고 확장할 수도 있다.
// 좋은 예, 인터페이스를 사용했다
Set<Son> sonSet = new LinkedHashSet<>();
// 나쁜 예, 클래스를 사용했다
LinkedHashSet<Son> sonSet = new LinkedHashSet<>();
인터페이스를 타입으로 사용하는 습관을 길러두면 프로그램이 훨씬 유연해질 것이다. 나중에 구현 클래스를 교체하고자 하다면 그저 새 클래스의 생성자를 호출해주기만 하면 된다.
예컨대 처음 선언은 다음처럼 바뀔 것이다.
Set<Son> sonSet = new HashSet<>();
주의할 점은 기존 코드와 새로운 클래스가 반드시 같은 기능을 제공해야한다는 점이다.
원래것보다 성능이 좋거나 멋진 신기능을 제공하기 때문일 수 있다. 예를 들어 hashMap을 참조하던 변수가 있다고 하자. 이를 EnumMap으로 바꾸면 속도가 빨라지고 순회 순서도 키의 순서와 같아진다. 단, EnumMap은 키가 열거 타입일 때만 사용할 수 있다.
적합한 인터페이스가 없다면 당연히 클래스로 참조해야 한다.
1. string과 bigInteger 같은 값 클래스가 그렇다.
2. 클래스로 기반으로 작성된 프레임워크가 제공하는 개체들(ex. OutputStream 등 java.io 패키지)
3. 인터페이스에 없는 특별한 메서드를 제공하는 클래스들 (ex. PriorityQueue 클래스는 Queue에 없는 기능을 제공한다)
실전에서는 주어진 객체를 표현할 적절한 인터페이스가 있는지 찾아서 그 인터페이스로 참조하면 더 유연하고 세련된 프로그램을 만들 수 있다. 물론 적합한 인터페이스가 없다면 클래스 계층구조 중 필요한 기능을 만족하는 가장 덜 구체적인(상위의) 클래스를 타입으로 사용하자