이펙티브 자바를 읽다가 Comparator<T> 인터페이스 코드를 봤습니다.
근데 @FunctionalInterface 어노테이션이 붙어있음에도 불구하고 두 개의 추상 메서드를 가지고 있는 겁니다!!
package java.util;
@FunctionalInterface
public interface Comparator<T> {
// abstract method
int compare(T o1, T o2);
// abstract method
boolean equals(Object obj);
// few default and static methods
}
헉 진짜 두 개네..!
사실 Java를 조금 만져보신 분들은 눈치를 채셨을 텐데요. 두 번째 추상 메서드가 equals 메서드라는 점이 눈에 띄었을 겁니다. 이점을 생각하면서 Comparator 인터페이스를 구현하는 과정을 살펴보면
- 구현할 클래스를 만든다.
- Comparator 인터페이스를 implements 한다.
- 인터페이스의 추상 메서드를 구현한다.
그러면 다음과 같은 코드가 작성됩니다.
class CustomComparator implements Comparator<Object> {
@Override
public int compare(Objects o1, Objects o2) {
return 0;
}
}
여기 까지만 작성해도 컴파일러는 아무 에러를 발생시키지 않습니다. 오잉 그럼 equals 메서드는?
사실 위 코드에는 숨겨진 부분이 있습니다. 바로 java.lang.Object를 상속받는 코드가 생략되어 있습니다. 그리고 Object 클래스에 equals 메서드가 이미 정의되어 있습니다.
class CustomComparator extends Object implements Comparator<Objects> {
@Override
public int compare(Objects o1, Objects o2) {
return 0;
}
}
따라서 컴파일러가 equals 메서드를 추상 메서드로 판단하지 않아 Comparator에 추상 메서드는 하나가 됩니다. (어차피 클래스로 구현하면 Object 클래스가 무조건 구현하니까!)
그렇다면 왜 Comparator 인터페이스에 equals 메서드를 선언해두었을까요? 이 이유는 javadoc에 있었습니다.
내용을 요약하면,
Object.equals(Object) 를 재정의 하지 않는 것이 항상 안전 합니다 . 그러나 경우에 따라 이 메서드를 재정의하면 프로그램에서 두 개의 서로 다른 비교기가 동일한 순서를 부과하도록 결정함으로써 성능이 향상될 수 있습니다.
즉, comp1.equals(comp2)는 sgn(comp1.compare(o1, o2))==sgn(comp2.compare(o1, o2))를 암시합니다.
이런 경우가 어떤 경우일지는 잘 상상이 되지 않지만 언젠간 도움이 될거라 생각합니다!
+ 추가)
Comparator 인터페이스에는 @FunctionalInterface 라는 애노테이션이 붙어있는데 이 애노테이션은 인터페이스가 함수형 인터페이스임을 나타냅니다. 함수형 인터페이스는 하나의 추상 메서드만 가지는 인터페이스로 Comparator 인터페이스는 두 개의 추상 메서드를 가지기 때문에 컴파일 오류가 날 것으로 보이지만 그렇지 않습니다.
Refernce
https://mkyong.com/java8/is-comparator-a-function-interface-but-it-has-two-abstract-methods/
https://docs.oracle.com/javase/6/docs/api/java/util/Comparator.html#equals%28java.lang.Object%29
https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html
'Java' 카테고리의 다른 글
1. 1 자바(Java) - Java의 정석 (0) | 2022.05.22 |
---|