2023. 11. 22. 22:46ㆍBook/이펙티브 자바
규약
1. equals 비교에 사용하느 정보가 변경되지 않았다면 hashCode는 매번 같은 값으 ㄹ리턴해야 한다.
2. 두 객체에 대하 equals가 같다면, hashCode의 값도 같아야 한다.
3. 두 객체에 대한 eqauls가 다르더라도(비효율적인 동작으 일으킬 수 있다.), hashCode의 값은 같을 수 있지만 해시 테이블 성능을 고려해 다른 값을 리턴하는 것이 좋다.
hashCode 재정의를 잘못햇을 때 크게 문제가 되는 조하은 두 번째다. equals 메서드는 값이 같다면 서로 다른 두 객체를 같다고 할 수 있다. 하지만 hashCode 메서드는 다르다고 판단하여 서로 다른 값을 반환한다.
public static void main(String[] args) {
Map<PhoneNumber, String> map = new HashMap<>();
PhoneNumber number1 = new PhoneNumber(123, 456, 7890);
map.put(number1, "son");
String s = map.get(new PhoneNumber(123, 456, 7890));
System.out.println(s);
}
==> null
number1과 new PhoneNumber(123, 456, 7890) eqauls 메서드를 사용하면 true를 리턴하고 논리적 동치이지만 hashMap에서 값을 꺼내올 때 hashCode 메서드를 사용하는데 서로 다른 값을 리턴해 number1의 value를 가져오지 못하는 것이다.
그럼 만약 hashCode를 재정의해서 무조건 같은 값을 반환하도록 하면 문제가 생길까?
public static void main(String[] args) {
Map<PhoneNumber, String> map = new HashMap<>();
PhoneNumber number1 = new PhoneNumber(123, 456, 7890);
PhoneNumber number2 = new PhoneNumber(155, 323, 3434);
//다른 인스턴스인데 같은 hashcode를 쓴다면?
System.out.println(number1.equals(number2));
System.out.println(number1.hashCode());
System.out.println(number2.hashCode());
map.put(number1, "son");
map.put(number2, "kim");
String s = map.get(number1);
System.out.println(s);
}
==> false, 12, 12, son
Map에서 value값을 잘 가져오는 것 처럼 보인다. 문제는 hashMap에서 value 값을 가져올대 배열에서 인덱스로 콕 집어서 빠르게 가져오는 게 아니라 같은 버킷에서 LinkedList 구조로 연결되어 있는 노드들을 순회하며 비교를 해 가져온다는 것이다. O(1) => O(n) 시간 복잡도가 늘어남
그러니 서로 다른 두 객체에서 다른 해시 값을 반환하는 것이 좋은 성능을 이끌어 낼 수 있다.
'Book > 이펙티브 자바' 카테고리의 다른 글
Item12 - toString을 항상 재정의하라 (1) | 2023.11.23 |
---|---|
Item11 - equals를 재정의하려거든 hashCode도 재정의하라(2) (3) | 2023.11.22 |
Item10 - equals는 일반 규약을 지켜 재정의하라(4) (1) | 2023.11.22 |
Item10 - equals는 일반 규약을 지켜 재정의하라(3) (1) | 2023.11.21 |
Item10 - equals는 일반 규약을 지켜 재정의하라(2) (1) | 2023.11.21 |