-
Notifications
You must be signed in to change notification settings - Fork 1
item 40 dodo4513
황도영 edited this page Apr 17, 2020
·
1 revision
- 자바가 기본으로 제공하는 애너테이션 중 보통의 프로그래머에게 가장 중요한 것은 @Override일 것이다. @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());
}
}
- main 메서드를 보면 똑같은 소문자 2개로 구성된 바이그램 26개를 10번 반복해 집합에 추가한 다음, 그 집합의 크기를 출력한다. Set은 중복을 허용하지 않으니 26이 출력될 거 같지만, 실제로는 260이 출력된다. 무언가 잘못됐다!
- 확실히 Bigram 작성자는 equals 메서드를 재정의하려 한 것으로 보이고 hashCode도 함께 재정의해야 한다는 사실을 잊지 않았다.
- 그런데 안타깝게도 equals를 ‘재정의(overriding)’한 게 아니라 ‘다중정의 (overloading)’해버렸다.
- Object의 equals를 재정의하려면 매개변수 타입을 Object로 해야만 하는데, 그렇게 하지 않은 것이다.
- 그래서 Object에서 상속한 equals와는 별개인 equals를 새로 정의한 꼴이 되었다. Object의 equals 는 == 연산자와 똑같이 객체 식별성(identity)만을 확인한다.
- 따라서 같은 소문자를 소유한 바이그램 10개 각각이 서로 다른 객체로 인식되고, 결국 260을 출력한 것이다.
@Override public boolean equals(Bigram b) {
return b.first == first && b.second == second;
}
상위 클래스의 메서드를 재정의하려는 모든 메서드에 @Override 애너테이션을 달자.
- 예외는 한 가지뿐이다. 구체 클래스에서 상위 클래스의 추상 메서드를 재정의할 때는 굳이 @Override를 달지 않아도 된다. 구체 클래스인데 아직 구현하지 않은 추상 메서드가 남아 있다면 컴파일러가 그 사실을 바로 알려주기 때문이다. 물론 재정의 메서드 모두에 @Override를 일괄로 붙여두는 게 좋아 보인다면 그래도 상관없다.