일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- 셀렉티
- @ExceptionHandler
- 상암동
- 서오릉맛집
- 압구정곱떡
- 데이트코스
- spring
- exceptionHandler
- @ControllerAdvice
- 토비의스프링
- 고기김치
- 녹는다녹아
- 서오릉
- 닭껍질만두
- 인생소고기집
- 상암동맛집
- 이펙티브자바
- 청춘면가
- EffectiveJava
- 앤드밀
- Java
- 아일랜드리솜
- 이속우화
- 맛집
- JUnit5
- 인생맛집
- 데이트
- 한우오마카세
- 압구정로데오맛집
- 경기족발
- Today
- Total
Hyeonuk_.log
[Effective Java] 규칙 9 equals를 재정의할 때는 반드시 hashCode도 재정의 하라 본문
[Effective Java] 규칙 9 equals를 재정의할 때는 반드시 hashCode도 재정의 하라
Hyeonuk_. 2022. 2. 25. 06:00
https://book.naver.com/bookdb/book_detail.nhn?bid=8064518
이펙티브 자바
JAVA, 더 깔끔하고, 정확하고, 안전하며, 재사용이 쉬운 코드로 만들자!『EFFECTIVE JAVA(이펙티브 자바)』는 효율적이면서도 잘 설계된 자바 프로그램을 구현하기 위해 알아야 할 지침 78가지를 소개
book.naver.com
이펙티브 자바 2판, 규칙9를 읽고 정리를 하려 한다. 규칙 9에서는 hashCode 메서드에 대해 말해주고 있다.
equals 메서드를 재정의하는 클래스는 hashCode 메서드도 반드시 재정의 해야한다.
Object 클래스 명세에서는 아래와 같이 hashCode 규약을 말하고 있다.
- 응용프로그램 실행 중에 같은 객체의 hashCode를 여러 번 호출하는 경우, equals가 사용하는 정보들이 변경되지 않았다면, 언제나 동일한 정수(interger)가 반환되어야 한다. 다만, 종료되었다가 다시 실행되어도 같은 값이 나올 필요는 없다.
- equals(Object) 메서드가 같다고 판정한 두 객체의 hashCode 값은 같아야 한다.
- equals(Object) 메서드가 다르다고 판정한 두 객체의 hashCode 값은 꼭 다를 필요는 없다. 그러나 서로 다른 hashCode 값이 나오면 해시 테이블의 성능이 향상될 수 있다는 점은 이해하고 있어야한다.
hashCode를 재정의하지 않으면 위반되는 핵심 규약은 두번째다. 같은 객체는 같은 해시코드값을 가져야 한다는 규약이 위반되는 것이다. 아래의 예를 봐보자
public class PhoneNumber {
private final short areaCode;
private final short prefix;
private final short lineNumber;
public PhoneNumber(int areaCode, int prefix, int lineNumber) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(prefix, 9999, "prefix");
rangeCheck(lineNumber, 9999, "lineNumber");
this.areaCode = (short) areaCode;
this.prefix = (short) prefix;
this.lineNumber = (short) lineNumber;
}
private static void rangeCheck(int arg, int max, String name) {
if(arg < 0 || arg > max) {
throw new IllegalArgumentException(name + ": " + arg);
}
}
@Override
public boolean equals(Object o) {
if(o == this) return true;
if(!(o instanceof PhoneNumber)) return false;
PhoneNumber pNumber = (PhoneNumber) o;
return pNumber.areaCode == areaCode
&& pNumber.prefix == prefix
&& pNumber.lineNumber == lineNumber;
}
// hashCode가 없다면 문제가 된다!!!!
public static void main(String argsp[]) {
Map<PhoneNumber, String> map = new HashMap<PhoneNumber, String>();
map.put(new PhoneNumber(707, 867, 5309), "Jenny");
System.out.println(map.get(new PhoneNumber(707, 867, 5309))); // null 리턴됨.
}
}
아래의 코드 추가 후에는 정상적으로 Jenny를 출력한다.
@Override
public int hashCode() {
int result = 17;
result = 31 * result + areaCode;
result = 31 * result + prefix;
result = 31 * result + lineNumber;
return result;
}
근데 왜 17이 있고 왜 31이 있을까???
책에서 말하는 지침들이 있다.
1. 17과 같은 0이 아닌 상수를 result라는 이름의 int 변수에 저장한다. (17은 임의의 값)
2. 객체 안에 있는 모든 중요 필드 f에 대해서(equals가 사용하는 필드) 아래의 절차를 시행한다.
A. 해당 필드에 대한 int 해시코드 c를 계산한다. (각 타입별로 방법이 기재되어 있다. 필요할 때 참고)
B. 위의 절차 A에서 계산된 해시코드 c를 result에 다음과 같이 결합한다.
result = 31 * result + c (31은 소수이면서 홀수이기에 선택, 만약 짝수였고 곱셈의 결과가 오버플로 되었다면 정보는 사라졌을 것. 2로 곱하는 것은 비트를 왼쪽으로 시프트하는 것과 같기 때문이다.)
3. result를 반환한다.
'Dev_.log > Java' 카테고리의 다른 글
[Effective Java] 규칙8 equals를 재정의할 때는 일반규약을 따르라 (0) | 2022.02.24 |
---|---|
알고 사용하자 Static이란 (0) | 2022.02.20 |