まず、Object クラス
が Java
、つまり # のすべてのクラスの親クラス (スーパークラス/基本クラス) であることを知っておく必要があります。 ##Java では、デフォルトですべてのクラスが
Object クラス を継承するため、
Object クラス に実装されているすべてのメソッドを直接使用できます。
equals メソッドは、
Object クラスによって実装される多くのメソッドの 1 つです。
Java11 API
1.1 等しいメソッド:
equals: これは
Object クラス のメソッドです。参照型です。後で持ってきても構いません。皆さん、
jdk ソース コードを見てください。
Integer と
String については、後ほど簡単に説明します (IDEA のソース コード実装を参照)
Object クラスがあり、
equals メソッドが使用できますね。なぜ
equals メソッドをオーバーライドする必要があるのでしょうか?これは、
Object クラスの
equals メソッドの実装メカニズムに依存します。
Object クラス の
equals メソッドの最下層が == を使用して実装されていることが明確にわかります。この使用法は、基本的なデータ型を比較するために通常使用する == の使用法と一致していると言われています。まず == の構文を見てみましょう:
#== 浮動小数点数の比較時にエラーが発生する場合もあります。これは、浮動小数点数の格納メカニズムが整数ファミリーの格納メカニズムと異なるためです。浮動小数点数自体は正確な値を表すことができません(具体的な理由は自分で確認できます) IEEE 754 ルール、ここでは展開しません)
注: Java
参照と
C ## を混同しないでください。 # 参照。C 参照は実際にはポインタ定数、つまり int* const
であるため、C
の参照は変数のエイリアスとしてのみ使用できます。 2.1 たとえば~
2 つの int を比較する場合、== を直接使用できます。それらが等しい場合、結果は
true になります。
まったく同じ属性を持つ 2 つのオブジェクトが取得された場合、==
を比較に使用するとエラーが発生します。 , 結果は false
ソースコード:
equals メソッドをオーバーライドする必要がある理由について大まかなアイデアが得られるはずです。
Object クラス は使いにくいものを提供するためです。 ~~3. 等しいソース コードを分析します:
書き直す前に、
public の定義を見てみましょう。 booleanquals(Object obj)関数: 他のオブジェクトがこのオブジェクトと「等しい」かどうかを示します。
equals メソッドは、null 以外のオブジェクト参照に対する等価性を実装します。
再帰性: null 以外の参照値
x は true
を返す必要があります。 対称性: null 以外の参照値
の場合、x.equals(y)
true
if を返し、y.equals(x)
returnstrue
のみを返す必要があります。 推移性: null 以外の参照値
、z
( の場合) x.equals(y)
returnstrue
y.equals(z)
returnstrue
, thenx.equals(z)
true
を返す必要があります。
一貫性: x.equals(y)
を複数回呼び出すと、常に null 以外の参照値 x
および y## が返されます。
#true または、オブジェクトの
equals 比較で使用される情報が変更されていない場合は、常に
false を返します。
x の場合、
x.equals(null) は
false を返す必要があります。
hashCode メソッドの通常の規約を維持するために、hashCode メソッドをオーバーライドする必要があります。
String クラス でオーバーライドされた
equals メソッドと、オーバーライドされた
Integer クラスを見てみましょう。
equals メソッドの記述:
//String类equals源代码: public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
true を返すということです。効率を向上させます。渡されたオブジェクトが現在のクラスのインスタンスである場合、さらなる判定が行われます。
for ループは文字列の各文字を順番に走査し、1 文字限り
false を返します。異なります。
Integer クラスの
equals ソース コードを見てみましょう:
//Integer类的equals源代码: public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
Integer クラス の
equals ソース コードは非常に単純です。受信オブジェクトが現在のクラスのインスタンスである限り、さらなる判断が行われます。等しい場合は
true が返され、そうでない場合は
false が返されます。
を例として、実践的なデモ 8 を行ってみましょう。
明らかに、
Integer はわかっています。 class は equals
メソッドをオーバーライドし、参照型です。 == を直接使用して参照型変数を比較すると、結果は false
となり、結果が true
であるかどうかを判断するために equals
が使用されます。これは、equals
メソッドをオーバーライドする必要性をよく示しています。 String クラス
自分で確認してください⑧。 4.equals メソッドを正しく書き直します:
は instanceof
より安全です) この時点で、
メソッドのさまざまなソース コードを基本的に分析しました。次のステップは、equals
メソッドを自分で実装することです。 ここでは 2 つの一般的な
書き換えメソッドを示します:
を使用して書き換えを実装します =equals
method
を使用して、オーバーライド equals
method
作成済みの四角形クラスの
Object クラスの equals
メソッドをオーバーライドして、四角形の長さと幅が等しい場合に # を返すようにします。 、
hashCode メソッドをオーバーライドし、
toString メソッドをオーバーライドして、四角形の長さと幅の情報を表示します。そしてクラスをテストします。
package com.test10_04; import java.util.Objects; class Rectangle { private double length; private double wide; public Rectangle() { //空实现 } public Rectangle(double length, double wide) { setLength(length); setWide(wide); } public double getLength() { return length; } public void setLength(double length) { assert length > 0.0 : "您的输入有误,长方形的长不能小于0"; this.length = length; } public double getWide() { return wide; } public void setWide(double wide) { assert wide > 0.0 : "您的输入有误,长方形的宽不能小于0"; this.wide = wide; } public double area() { return this.length * this.wide; } public double circumference() { return 2 * (this.wide + this.length); } public boolean equals(Object obj) { if (this == obj) { //判断一下如果是同一个对象直接返回true,提高效率 return true; } if (obj == null || obj.getClass() != this.getClass()) { //如果传进来的对象为null或者二者为不同类,直接返回false return false; } //也可以以下方法: // if (obj == null || !(obj instanceof Rectangle)) { //如果传进来的对象为null或者二者为不同类,直接返回false // return false; // } Rectangle rectangle = (Rectangle) obj; //向下转型 //比较长宽是否相等,注意:浮点数的比较不能简单地用==,会有精度的误差,用Math.abs或者Double.compare return Double.compare(rectangle.length, length) == 0 && Double.compare(rectangle.wide, wide) == 0; } public int hashCode() { //重写equals的同时也要重写hashCode,因为同一对象的hashCode永远相等 return Objects.hash(length, wide); //调用Objects类,这是Object类的子类 } public String toString() { return "Rectangle{" + "length=" + length + ", wide=" + wide + '}'; } } public class TestDemo { public static void main(String[] args) { Rectangle rectangle1 = new Rectangle(3.0, 2.0); Rectangle rectangle2 = new Rectangle(3.0, 2.0); System.out.println(rectangle1.equals(rectangle2)); System.out.println("rectangle1哈希码:" + rectangle1.hashCode() + "\nrectangle2哈希码:" + rectangle2.hashCode()); System.out.println("toString打印信息:" + rectangle1.toString()); } }
具体的な実装アイデアはコード内に明確に記載されています。
getClass と instanceof という 2 つの実装メソッドの長所と短所を分析することに焦点を当てましょう:
コード ロジックを簡略化します: この単純なコードに焦点を当てましょう
//getClass()版本 public class Student { private String name; public void setName(String name) { this.name = name; } @Override public boolean equals(Object object){ if (object == this) return true; // 使用getClass()判断对象是否属于该类 if (object == null || object.getClass() != getClass()) return false; Student student = (Student)object; return name != null && name.equals(student.name); }
//instanceof版本 public class Student { private String name; public void setName(String name) { this.name = name; } @Override public boolean equals(Object object){ if (object == this) return true; // 通过instanceof来判断对象是否属于类 if (object == null || !(object instanceof Student)) return false; Student student = (Student)object; return name!=null && name.equals(student.name); } }
実際、どちらの解決策も有効ですが、違いは次のとおりです
getClass()
instanceof はオブジェクトが同じクラスまたはそのサブクラスになることを許可するため、equals メソッドが親クラスとサブクラスになり、equals 演算も実行できます。このとき、サブクラスがequalsメソッドを再定義すると、親クラスのオブジェクトequlasになる可能性があります。以下に示すように、サブクラスのオブジェクトはtrueですが、親クラスのオブジェクトのサブクラスオブジェクトのequlasはfalseになります。ここでは
getClass() が使用されていることに注意してください
戻り値は両方とも
であり、期待値 (クラスが異なっていても、false
である必要があります) を
に置き換えます。試す: ############
実行結果: 1 つは true
、もう 1 つは false
です。明らかに問題があります。
理由は次のとおりです。 instanceof
の構文は次のようになります。
オブジェクトがオブジェクトのインスタンスである場合クラスの結果は true
になります。ただし、このオブジェクトがそのサブクラスのインスタンスである場合、結果も true
になるという特性もあります。これが上記のバグにつながります。つまり、比較対象の 2 つのオブジェクトに親子関係がある場合、instanceof
によって問題が発生する可能性があります。 **さらに詳しく学ぶ必要がある友達は自分で学ぶことができるため、equals
メソッドを書き直すときは、getClass
を使用して達成することをお勧めします。
equals
メソッドを書き換える場合は、hashCode
メソッドをオーバーライドする必要があります。
以上がJavaでequalsメソッドを正しくオーバーライドする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。