EqualsとHashCodeの使用法と注意事項を一度に理解する
EqualsとHashCodeの概念と使用法は常に非常にあいまいでしたが、今はいくつかの情報を収集して要約する時間があります。
等しいについて
Objectクラスのデフォルトの実装は次のとおりです。returnthis==obj。つまり、thisとobjが同じオブジェクトを参照している場合にのみtrueを返します。
また、2つのオブジェクトが同等であるかどうかを判断するために、それらの一意性を検証するのではなく、equalsを使用する必要があることがよくあります。このように、独自のクラスを実装する場合は、equalsを書き換える必要があります。もちろん、equalsを書き換える場合は、特にhashSet、HashMap、HashTable、その他の関連操作などのヒープハッシュストレージ構造で、対応するhashCodeを書き換えることをお勧めします。次に、javaは、equalを書き換える場合はhashCodeを書き換える必要があることを明確に規定しています。これについては、以下で説明します。
Java言語仕様では、equalsに次の特性が必要です。
自反性:对于任何非空引用 x,x.equals(x) 应该返回 true。
对称性:对于任何引用 x 和 y,当且仅当 y.equals(x) 返回 true,x.equals(y) 也应该返回 true。
传递性:对于任何引用 x、y 和 z,如果 x.equals(y)返回 true,y.equals(z) 也应返回同样的结果。
一致性:如果 x 和 y 引用的对象没有发生变化,反复调用 x.equals(y) 应该返回同样的结果。
对于任意非空引用 x,x.equals(null) 应该返回 false。
equalsメソッドをオーバーライドするときは、上記の仕様に従ってください。たとえば、次の使用法です。
public boolean equals(Object obj) {
if (this == obj) return true;
if ((obj==null)||(this.getClass()!=obj.getClass()))
return false;
User user = (User) obj;
return this.id==user.id&&this.name.equals(u ser.name);
}
HashCodeについて
HashCodeの役割と注意事項については、この記事全体を読むだけで十分です。読んだ後、このブロガーはうまく書いていると思います。https: //blog.csdn.net/をご覧になることをお勧めします。
lijiecao0226 / article / details / 24609559
HashCodeを正しく書き直してください
参照ドキュメント:https
://blog.csdn.net/benjaminzhang666/article/details/9468605#注:HashCodeを書き換える場合、2つの異なるオブジェクトに対して同じ値に書き換えることはできません(ここでは、内部メンバーの属性値は異なる同じ)、等しいものを比較する必要はありません。HashCodeを書き換えるときは、メンバー属性をできるだけ計算することをお勧めします。これにより、ハッシュストレージ構造のset操作を実行するときに必要ありません。等しい値を計算するには、HashCodeに基づいてコレクションにオブジェクトを追加するかどうかを直接判断できます。もちろん、メンバーが多いオブジェクトの場合、HashCodeはより複雑であり、パフォーマンスにも影響します。
例を以下に示します
HashCodeをオーバーライドするときに同じ値を返します
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object obj) {
System.out.println(this.name +"开始比较equals");
if (this==obj)
return true;
if (obj!=null&&!(getClass()!=obj.getClass()))
return false;
Student student = (Student) obj;
return this.name.equals(student.name)&&this.age==student.age;
}
public int hashCode(){
System.out.println(this.name +"开始计算HashCode");
return 31*age;
}
}
public class HashCodeAndEqualsTest {
public static void main(String[] args) {
Set<Student> students = new HashSet<>();
Student student1 = new Student("菜鸟", 25);
Student student2 = new Student("大佬", 25);
students.add(student1);
students.add(student2);
System.out.println(students);
}
}
演算結果:
菜鸟开始计算HashCode
大佬开始计算HashCode
大佬开始比较equals
[Student{
name='菜鸟', age=25}, Student{
name='大佬', age=25}]
HashCodeを書き換えると、すべての属性がカウントされ、hashCodeが変更されます
public int hashCode(){
System.out.println(this.name +"开始计算HashCode");
return 31*age+this.name.hashCode();
}
演算結果:
菜鸟开始计算HashCode
大佬开始计算HashCode
[Student{
name='大佬', age=25}, Student{
name='菜鸟', age=25}]
メンバー変数が異なるオブジェクトの場合、2番目のメソッドは最初のメソッドよりも少ない値を計算するため、計算パフォーマンスが向上することがわかります。
要約:
- HashCodeをオーバーライドする場合、同じ値を返すことはできませんが、クラスのメンバープロパティを含める必要があります
- HashCodeを書き換える場合、クラスのメンバー属性を線形結合できます。つまり、hash= int形式の属性****1 +C1* int形式の属性2 +C2* int形式の属性3 +...( C1、C2係数については、線形代数を学んだ人にとってはより明確です〜)
- 連結後の値は、整数の式の範囲を超えることはできないことに注意してください。
- 参照プロパティについては、文字列タイプと同様に、そのHashCodeを直接呼び出すことができ、参照を直接使用できます。
- 線形結合を使用すると、さまざまなオブジェクトパラメータのハッシュ競合を回避し、ハッシュストレージ構造の使用率を向上させることができます