@Override는 상위 타입의 메서드를 재정의했음을 뜻하는 애너테이션으로, 메서드 선언에만 달 수 있다.
이 애너테이션을 일관되게 사용하면 여러가지 악명 높은 버그를 예방할 수 있다.
public class Bigram {
private final char first;
private final char second;
public Bigram(char first, char second) {
this.first = first;
this.second = second;
}
public boolean equals(Bigram b) {
return b.first == first && b.second == second;
}
public int hashCode() {
return 31 * first + second;
}
public static void main(String[] args) {
Set<Bigram> s = new HashSet<>();
for (int i = 0; i < 10; i++)
for (char ch = 'a'; ch <= 'z'; ch++)
s.add(new Bigram(ch, ch));
System.out.println(s.size()); // 26이 아닌 260이 출력된다.
}
}
위의 예제는 equals를 재정의할 의도였지만, 재정의(overriding)
이 아닌 다중정의(overloading)
를 하였다.
Object의 equals를 재정의하려면 매개변수 타입을 Object로 해야 하는데 Bigram으로 했기 때문이다.
그래서 중복을 허용하지 않는 Set이지만, Object의 equals는 객체 식별성만을 확인하기 때문에 같은 소문자를 서로 다른 객체로 인식하여 모두 Set에 추가하게 되는 것이다.
이러한 오류는 @Override 애너테이션을 사용하면, 컴파일러가 잡아주기 때문에 곧장 올바르게 수정할 수 있다!
상위 클래스의 메서드를 재정의하려는 모든 멤서드에 @Override
애너테이션을 달자.
단, 구체 클래스에서 상위 클래스의 추상 메서드를 재정의할 때는 굳이 달지 않아도 컴파일러가 잡아주므로 달지 않아도 된다. 물론 달아도 된다.
@Override는 클래스 뿐만 아니라 인터페이스의 메서드를 재정의할 때도 사용할 수 있다.
디폴트 메서드
를 지원하기 시작하면서, 인터페이스 메서드를 구현한 메서드에도 @Override를 다는 습관을 들이면 시그니처가 올바른지 재차 확신할 수 있다.
🔖 핵심 정리
재정의한 모든 메서드에 @Override 애너테이션을 의식적으로 달면 실수했을 때 컴파일러가 바로 알려줄 것이다.
딱 한 가지 예외는 있다.
구체 클래스에서 상위 클래스의 추상 메서드를 재정의한 경우엔 이 애너테이션을 달지 않아도 된다.
이때는 구체 클래스에서 추상 메서드가 남아 있다면 컴파일러가 그 사실을 바로 알려주기 때문이다.
그러나 단다고 해서 해로울 것도 없다.