@Override
이 애노테이션이 달렸다는 것은 메소드 선언에만 달 수 있으며, 상위 타입의 메소드를 재정의했음을 뜻한다.
상위 클래스의 메소드를 재정의하려는 모든 메소드에 @Override 애노테이션을 꼭 달자.
예외를 두자면 구체 클래스에서 상위 클래스의 추상 메소드를 재정의 할 때는 굳이 @Override를 달 필요는 없다.
구체 클래스인데 아직 구현하지 않은 추상 메소드가 남았다면 컴파일러가 알려주기 때문이다.
내 견해는 다 붙히기로 마음먹었다면 일괄적으로 붙혀두는게 좋을 것 같다.
일관되게 @Override 애노테이션을 사용하면 두 가지 좋은 점이 있다.
1. 실수로 다중정의(Overloding)해버리는 상황을 막을 수 있다.
2. 컴파일러가 재정의하려는 메소드와 다르거나 그런 메소드가 없는 경우 컴파일 오류를 발생시켜준다.
//두 개의 char를 저장
public class Bigram {
private final char first;
private final char second;
public Bigram(char first, char second) {
this.first = first;
this.second = second;
}
//다중정의한 equals
public boolean equals(Bigram b) {
return b.first == first && b.second == second;
}
//올바르게 Override한 equals
@Override
public boolean equals(Object o) {
if (!(o instanceof Bigram))
return false;
Bigram b = (Bigram) o;
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());
}
}
메인문을 보면 (a,a)~(z,z) 즉 26개의 Bigram을 10번 저장했고, HashSet을 사용한 것을 보아 중복이 허용되지 않으니
26의 출력을 기대했을 것이다. 하지만 위 코드는 equals를 정의는 했지만 Overriding하지 않았다.
그리고 Objects의 equals를 재정의 하려면 매개변수 타입을 Object로 해야만 하는데, 지켜지지 않았기 때문에 다중정의된 것이다.
따라서 Bigram의 equals는 Object의 equals를 HashSet에 추가할 때 사용하고 ==연산자로 식별성만 확인하여 260을 출력한다.
@Override 애노테이션을 붙혔다면 컴파일 시점에서 오류를 알아차릴 수 있었다.
클래스뿐 아니라 인터페이스의 메소드를 재정의 할때도 사용하자
자바8부터 디폴트 메소드를 지원하며, interface메소드를 구현한 메소드에도 애노테이션을 달면 시그니처가 올바른지 확신할 수 있다.
그리고 추상 클래스나 인터페이스에서도 상위 클래스나 상위 인터페이스의 메소드를 재정의하는 모든 메소드에 @Override를 다는게 좋다.
상위 클래스가 구체 클래스든 추상 클래스든 마찬가지다.
예를들어 Set 인터페이스는 Collection 인터페이스를 확장했지만 새로 추가한 메소드는 없다.
따라서 모든 메소드 선언에 @Override를 달아 실수로 추가한 메소드가 없음을 보장했다.
기타 추가사항
IDE들은 관련설정을 활성화 해두면 @Override가 달리지 않은 메소드가 실제로는 재정의 했다면 경고를 주게할 수 있다.
컴파일 오류의 보완재 역할이다. Intellij MAC기준으로 preferences - Editor - Inspections 에서 아래문항을 체크하면 된다.

* 위 글은 EffectiveJava 3/E 책 내용을 정리한 글로, 저작권 관련 문제가 있다면 댓글로 남겨주시면 즉각 삭제조치 하겠습니다.
'Reading > Effective Java' 카테고리의 다른 글
| [Effective-Java] Item 42. 익명 클래스보다는 람다를 사용하라 (0) | 2021.10.31 |
|---|---|
| [Effective-Java] Item 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라. (0) | 2021.10.31 |
| [Effective-Java] Item 39. 명명 패턴보다 애너테이션을 사용하라 (0) | 2021.10.31 |
| [Effective-Java] Item 38. 확장할 수 있는 열거 타입이 필요하면 인터페이스를 사용하라 (0) | 2021.10.31 |
| [Effective-Java] Item 37. ordinal 인덱싱 대신 EnumMap을 사용하라 (0) | 2021.10.31 |