ホームページ  >  記事  >  Java  >  Javaでequalsメソッドを正しくオーバーライドする方法

Javaでequalsメソッドを正しくオーバーライドする方法

WBOY
WBOY転載
2023-05-09 11:19:261322ブラウズ

1. イコール法とは何ですか?

まず、Object クラスJava、つまり # のすべてのクラスの親クラス (スーパークラス/基本クラス) であることを知っておく必要があります。 ##Java では、デフォルトですべてのクラスが Object クラス を継承するため、Object クラス に実装されているすべてのメソッドを直接使用できます。 equals メソッドは、Object クラスによって実装される多くのメソッドの 1 つです。

次のスクリーンショットは

Java11 API

Javaでequalsメソッドを正しくオーバーライドする方法

オブジェクト クラスのすべてのメソッドから取得したものです:

Javaでequalsメソッドを正しくオーバーライドする方法

1.1 等しいメソッド:

  • equals: これは Object クラス のメソッドです。参照型です。後で持ってきても構いません。皆さん、jdk ソース コードを見てください。

  • デフォルトでは、アドレスが等しいかどうかが判断されます (基になるのは参照型変数の本質は、オブジェクトのアドレスを格納することです。C/C の知識がある人はよく知っているはずです)。このメソッドは、オブジェクトの内容が等しいかどうかを判断するためにサブクラスでオーバーライドされることがよくあります。たとえば、

    IntegerString については、後ほど簡単に説明します (IDEA のソース コード実装を参照)

2。メソッドを書き換えますか?

Object クラスがあり、equals メソッドが使用できますね。なぜ equals メソッドをオーバーライドする必要があるのでしょうか?これは、Object クラスequals メソッドの実装メカニズムに依存します。

Javaでequalsメソッドを正しくオーバーライドする方法

Object クラス equals メソッドの最下層が == を使用して実装されていることが明確にわかります。この使用法は、基本的なデータ型を比較す​​るために通常使用する == の使用法と一致していると言われています。まず == の構文を見てみましょう:

  • == は、基本的なデータ型の等しいかどうかの比較、つまり単純な値の比較にのみ使用できます。

    #== 浮動小数点数の比較時にエラーが発生する場合もあります。これは、浮動小数点数の格納メカニズムが整数ファミリーの格納メカニズムと異なるためです。浮動小数点数自体は正確な値を表すことができません(具体的な理由は自分で確認できます) IEEE 754 ルール、ここでは展開しません)
  • したがって、基本的なデータ型の値を単純に比較する場合は == を使用できますが、上で述べたように、参照データ型を比較す​​る場合はこれを行うことはできません。参照データ型は基本的にオブジェクトのアドレスを参照/保存するために使用されるため、
  • C/C へのポインタとして扱うことができると述べました。
(ここでは Java にはポインターがないと言われていますが、個人的には単に名前が違うだけだと思います)

注: Java 参照と
C ## を混同しないでください。 # 参照。C 参照は実際にはポインタ定数、つまり int* const であるため、C の参照は変数のエイリアスとしてのみ使用できます。 2.1 たとえば~2 つの int を比較する場合、== を直接使用できます。それらが等しい場合、結果は

true

となり、

new の場合、結果は

true になります。 まったく同じ属性を持つ 2 つのオブジェクトが取得された場合、== を比較に使用するとエラーが発生します。 , 結果は false ソースコード:

実行結果:

Javaでequalsメソッドを正しくオーバーライドする方法

ここに進むと、オブジェクトを比較するときに

equalsJavaでequalsメソッドを正しくオーバーライドする方法 メソッドをオーバーライドする必要がある理由について大まかなアイデアが得られるはずです。

Object クラス

は使いにくいものを提供するためです。 ~~3. 等しいソース コードを分析します: 書き直す前に、

Java API

:

public の定義を見てみましょう。 booleanquals(Object obj)関数: 他のオブジェクトがこのオブジェクトと「等しい」かどうかを示します。
equals メソッドは、null 以外のオブジェクト参照に対する等価性を実装します。

再帰性: null 以外の参照値

x
    ,
  • x .equals(x)

    true を返す必要があります。 対称性: null 以外の参照値

    x
  • および
  • y

    の場合、x.equals(y) trueif を返し、y.equals(x)returnstrue のみを返す必要があります。 推移性: null 以外の参照値

    #x
  • y

    z ( の場合) x.equals(y)returnstruey.equals(z)returnstrue, thenx.equals(z) true を返す必要があります。

  • 一貫性: x.equals(y) を複数回呼び出すと、常に null 以外の参照値 x および y## が返されます。 #true または、オブジェクトの equals 比較で使用される情報が変更されていない場合は、常に false を返します。

  • null 以外の参照値

    x の場合、x.equals(null)false を返す必要があります。

クラス Object の equals メソッドは、オブジェクト上で最も特徴的な可能な同値関係を実装します。つまり、null 以外の参照値 x と y について、x の場合にのみ実装されます。 y が同じオブジェクトを参照する場合 (x == y の値が true の場合)、このメソッドは true を返します。

注: 通常、このメソッドをオーバーライドする場合は、等しいオブジェクトには等しいハッシュ コードが必要であるという

hashCode メソッドの通常の規約を維持するために、hashCode メソッドをオーバーライドする必要があります。

Javaでequalsメソッドを正しくオーバーライドする方法

次に、

String クラス でオーバーライドされた equals メソッドと、オーバーライドされた Integer クラスを見てみましょう。 equals メソッドの記述:

Javaで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 ソース コードを見てみましょう:

Javaでequalsメソッドを正しくオーバーライドする方法

//Integer类的equals源代码:
 public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

Integer クラス equals ソース コードは非常に単純です。受信オブジェクトが現在のクラスのインスタンスである限り、さらなる判断が行われます。等しい場合は true が返され、そうでない場合は false が返されます。

Integer クラス

を例として、実践的なデモ 8 を行ってみましょう。

Javaでequalsメソッドを正しくオーバーライドする方法明らかに、

Integer はわかっています。 class

equals メソッドをオーバーライドし、参照型です。 == を直接使用して参照型変数を比較すると、結果は false となり、結果が true であるかどうかを判断するために equals が使用されます。これは、equals メソッドをオーバーライドする必要性をよく示しています。 String クラス 自分で確認してください⑧。 4.equals メソッドを正しく書き直します:

(結論を先に話します。

getClass()

instanceof より安全です) この時点で、

equals

メソッドのさまざまなソース コードを基本的に分析しました。次のステップは、equals メソッドを自分で実装することです。 ここでは 2 つの一般的な

equals

書き換えメソッドを示します:

  • instanceof

    を使用して書き換えを実装します =equals method

  • getClass

    を使用して、オーバーライド equalsmethod

  • 次のシナリオがあると仮定します。

作成済みの四角形クラスの

Objec

t クラスの 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 つの実装メソッドの長所と短所を分析することに焦点を当てましょう:

コード ロジックを簡略化します: Javaでequalsメソッドを正しくオーバーライドする方法この単純なコードに焦点を当てましょう

//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

であり、期待値 (クラスが異なっていても、Javaでequalsメソッドを正しくオーバーライドする方法false

である必要があります)

instanceof

に置き換えます。試す: ############

実行結果: 1 つは true、もう 1 つは false です。明らかに問題があります。

Javaでequalsメソッドを正しくオーバーライドする方法

理由は次のとおりです。
instanceof の構文は次のようになります。
オブジェクトがオブジェクトのインスタンスである場合クラスの結果は true になります。ただし、このオブジェクトがそのサブクラスのインスタンスである場合、結果も true になるという特性もあります。これが上記のバグにつながります。つまり、比較対象の 2 つのオブジェクトに親子関係がある場合、instanceof によって問題が発生する可能性があります。 **さらに詳しく学ぶ必要がある友達は自分で学ぶことができるため、equals メソッドを書き直すときは、getClass を使用して達成することをお勧めします。

equals メソッドを書き換える場合は、hashCode メソッドをオーバーライドする必要があります。

以上がJavaでequalsメソッドを正しくオーバーライドする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。