@Override
import java.util.*;
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;
}
// 똑같은 소문자 2개로 구성된 바이그램 26개를 10번 바복해 집합에 추가 -> 그 집합의 크기 출력
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
은 중복을 허용하지 않으니 26이 출력될 것이라 기대하지만, 실제로는 260이 출력된다.
왜냐하면, equals
메서드를 재정의(overriding) 한 게 아니라, 다중 정의(overloading) 하였기 때문이다.
객체 식별성(identity)를 확인하는 Object의 equals
를 재정의하려면 매개변수 타입을 Object로 해야 하는데 그렇게 하지 않은 것이다. 따라서, 같은 소문자를 소유한 바이그램 10개 각각이 서로 다른 객체로 인식된 것이다.
@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;
}
그러니 상위 클래스의 메서드를 재정의하려는 모든 메서드에 @Override
애너테이션을 달자.
@Override
를 달지 않아도 되는 단 하나의 예외구체 클래스에서 상위 클래스의 추상 메서드를 재정의할 때는 @Override
를 달지 않아도 된다. 구체 클래스인데 아직 구현하지 않은 추상 메서드가 있다면 컴파일러가 이를 알려주기 때문이다.
하지만 @Override
를 일괄적으로 다는 게 좋아 보인다면 달아줘도 상관없다.
@Override
를 붙이는 게 좋은 이유
@Override
를 붙여주는 것이 좋다. 이렇게 하면 메서드의 시그니처가 올바른지 재차 확신할 수 있기 때문이다.@Override
를 붙여주는 게 좋다.