💡 재정의한 모든 메서드에 @Override 애너테이션을 의식적으로 달면, 실수했을 때 컴파일러가 알려줄 것이다.
📌 As-is. @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());
}
}
위 코드는 정상적으로 동작할 것 같으나, 그렇지 않다.
Set은 중복을 허용하지 않으므로 s.size()가 26이 나올 것이라 기대하겠지만 실제로는 260이 출력된다.
equals와 hashCode를 재정의하는 것은 잊지 않았지만, Overriding이 아니라 Overloading을 해버린 것이 문제다.
이 오류는 컴파일러가 찾아낼 수 있지만, 그러려면 Obejct.equals를 재정의한다는 의도를 명시해야 한다.
📌 To-be
@Override public boolean equals(Object o) {
if (!(o instanceof Bigram))
return false;
Bigram b = (Bigram) o;
return b.first == first && b.second == second;
}
- 상위 클래스의 메서드를 재정의하려는 모든 메서드에 @Override 애너테이션을 달자.
- 구체 클래스에서 추상 메서드 구현 시에는 굳이 달지 않아도 된다.
- 하지만 단다고 해서 해로울 것도 없다. (대부분 IDE에선 자동으로 붙이거나, 사용하도록 부추긴다.)
- 추상 클래스나 인터페이스에서 상위 클래스나 인터페이스의 메서드를 재정의하는 경우엔 모든 메서드에 붙이는 것이 좋다.