Effective Java-すべてのオブジェクトの共通メソッドを再定義する場合(2):equals、hashCodeを再定義します.
8271 ワード
equalsを再定義する場合はhashCodeを再定義します
equalsを再定義するクラスはすべてhashCodeを再定義する必要があります.それ以外の場合、hashCodeの一般的な規則に違反する可能性があります.このクラスのインスタンスをHashMapやHashSetなどの集合要素として使用する場合に問題が発生します.
オブジェクト・リストの約定
equals(Object)가 두 객체를 같다고 판단했다면, 두 객체의 hashCode는 똑같은 값을 반환해야한다.
Map<PhoneNumber, String> m = new HashMap<>();
m.put(new PhoneNumber(707, 867, 5309), "제니");
// 아래 코드를 실행해도 "제니"는 나오지 않는다. (null 반환)
// 논리적 동치인 이 객체는 hashCode를 정의하지 않았기 때문에 두 객체가 서로 다른 해시코드를 반환하여 두 번째 규약을 지키지 못한다.
m.get(new PhoneNumber(707, 867, 5309));
.
.
.
@Override
public int hashCode() {return 42;}
// 이 코드처럼 hashCode를 정의하면 모든 객체가 해시테이블의 버킷 하나에 담겨 마치 연결리스트처럼 동작한다.
// 그러면 평균 수행 시간이 O(1)인 해시테이블이 O(n)으로 느려져 쓸 수 없게 된다.
// hashCode 함수는 서로 다른 인스턴스에 대해 다른 해시코드를 반환해야한다.
hash値のセット(HashSet,HashMap,HashTable)を使用すると、比較オブジェクトが論理的に同じかどうかを判断する際に、次のような処理が行われます.hashCodeメソッドの戻り値はまず一致し,equalsメソッドの戻り値はtrueでなければ論理的に同じオブジェクトと判断できない.
最初の例では、hashCodeメソッドが定義されていないため、ObjectクラスのhashCodeメソッドが使用されます.
ObjectクラスのhashCodeメソッドは、オブジェクトの一意のアドレス値をint値として返すので、各オブジェクトは異なる値を返します.
したがって,2つのオブジェクトでequals比較を行うと,別のオブジェクトと判断する.
HashCodeメソッドの作成
理想的な関数は、与えられた異なるインスタンスを32ビット整数の範囲に均一に割り当てるべきである.要領を了解する.
ex) result = 30 * result + c;
派生フィールドは、ハッシュコード計算から除外できます.つまり、他のフィールドから計算できるすべてのフィールドは無視できます.また、equals比較に使用されないフィールド「必須」は除外されます.そうでなければhashCodeの2番目の約束に違反します.
PhoneNumberクラスに適用
@Override
public int hashCode() {
int result = Short.hashCode(areaCode);
result = 31 * result + Short.hashCode(prefix);
result = 31 * result + Short.hashCode(lineNum);
return result;
}
2−2の積31 resultは、フィールドに乗算された順序に従って結果値を変更する.その結果、クラスに複数の類似フィールドがある場合、ハッシュ効果を大幅に向上させることができる.たとえば、StringのhashCodeに乗算が実装されていない場合、すべてのアナック(構成されたスペルが同じで、順序が異なる文字列のみ)のhashCodeは同じになります.乗じた数字を31とした理由は31が奇数で少数であった.この数字が偶数でオーバーフローが発生すると、情報が失われます.2を掛けるとShift演算になるからです.小数に乗る原因は明確ではありませんが、伝統的にはそうしています.その結果、31を乗じると、この乗算の代わりにShift演算と減算を用いて最適化することができる.(31 iは(i<5)−iに等しい.)現在の仮想マシンでは、この最適化が自動的に行われます.PhoneNumberインスタンスの3つのコアフィールドのみを使用して単純な計算を行います.プロセス中に非決定的な要因がないので、一致するPhoneNumberインスタンスは同じハッシュコードを有するに違いない.
Objectsクラスは、任意の数のオブジェクトを受信し、ハッシュコードを計算する静的方法hashを提供する.
hashメソッドを使用してhashcodeの行を記述できる場合、速度は遅くなります.なぜなら、入力に基本タイプがあれば、ミシンや糸を外すこともあるからです.
@Override
public int hashCode() {
return Objects.hash(lineNum, prefix, areaCode);
}
クラスがfinalであり、ハッシュコードを計算するコストが高い場合は、毎回再計算するのではなく、キャッシュの方法を考慮する必要があります.このタイプのオブジェクトが主にハッシュキーとして使用される場合、インスタンスの作成時にハッシュコードを計算する必要があります.Reference
この問題について(Effective Java-すべてのオブジェクトの共通メソッドを再定義する場合(2):equals、hashCodeを再定義します.), 我々は、より多くの情報をここで見つけました https://velog.io/@shinmj1207/Effective-Java-모든-객체의-공통-메서드2-equals를-재정의하려거든-hashCode도-재정의하라テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol