ホームページ  >  記事  >  Java  >  Java 改善記事 ---equals() メソッドの概要

Java 改善記事 ---equals() メソッドの概要

黄舟
黄舟オリジナル
2017-02-07 16:48:401244ブラウズ

equals()

スーパークラスObjectにはこのequals()メソッドがあり、このメソッドは主に2つのオブジェクトが等しいかどうかを比較するために使用されます。このメソッドのソース コードは次のとおりです:

public boolean equals(Object obj) {    return (this == obj);
    }

すべてのオブジェクトには識別 (メモリ アドレス) とステータス (データ) があることがわかっており、「==」は 2 つのオブジェクトのメモリ アドレスを比較するため、equals() を使用します。 Object のメソッド 2 つのオブジェクトのメモリ アドレスが等しいかどうかを比較します。つまり、object1.equals(object2) が true の場合、equals1 と equals2 は実際に同じオブジェクトを参照していることを意味します。 Object のquals() メソッドは基本的な要件の一部を満たしている場合もありますが、現時点では 2 つのオブジェクトを比較する場合、実際には Object のquals() メソッドは使用できないことに注意する必要があります。以前の JDK では、String や Math などのカプセル化クラスが、equals() メソッドを書き直しました。

以下は String のquals() メソッドです:

public boolean equals(Object anObject) {    if (this == anObject) {        return true;
    }    if (anObject instanceof String) {
        String anotherString = (String)anObject;        
        int n = count;        
        if (n == anotherString.count) {        
        char v1[] = value;        
        char v2[] = anotherString.value;        
        int i = offset;        
        int j = anotherString.offset;        
        while (n-- != 0) {            
        if (v1[i++] != v2[j++])            
        return false;
        }       
         return true;
        }
    }    return false;
    }

このコード セグメントの場合: if (v1[i++] != v2[j++]) return false; String の等しい() メソッドが次のとおりであることがわかります。参照比較ではなくコンテンツ比較を実行しました。他のカプセル化クラスについても同様です。

Java 仕様では、equals() メソッドの使用は次の規則に従う必要があります:


equals メソッドは、null 以外のオブジェクト参照に対する等価性を実装します:

1.参照値 x、x.equals(x) は true を返す必要があります。

2. 対称性: null 以外の参照値 x および y については、y.equals(x) が true を返す場合に限り、x.equals(y) は true を返す必要があります。

3. 推移性: null 以外の参照値 x、y、z について、x.equals(y) が true を返し、y.equals(z) が true を返す場合、x.equals(z) は次のようになります。 trueを返します。

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

5. null 以外の参照値 x の場合、x.equals(null) は false を返す必要があります。

上記のルールについては、使用中は遵守していただくことが最善です。遵守しないと、予期しないエラーが発生します。

Java で比較するには、比較のタイプに応じて適切な比較メソッドを選択する必要があります:


1) object フィールドで、equals メソッドを使用します。
2) タイプセーフな列挙。equals または == を使用します。
3) null の可能性があるオブジェクト フィールド: == と等しいを使用します。
4) 配列フィールド: Arrays.equals を使用します。
5) float と double を除くプリミティブ データ型: == を使用します。
6) Float 型: Float.foatToIntBits を使用して int 型に変換し、その後 == を使用します。
7) Double 型: Double.doubleToLongBit を使用して Long 型に変換し、その後 == を使用します。


なぜ6)と7)を変換する必要があるかについては、対応するカプセル化クラスのequals()メソッドを参照できます。 以下はFloatクラスです:

public boolean equals(Object obj) {    return (obj instanceof Float)
           && (floatToIntBits(((Float)obj).value) == floatToIntBits(value));
    }

まあ、ポイントは2つあります。その中で言及されています:

However, there are two exceptions:If f1 and f2 both representFloat.NaN, then the equals method returnstrue, 
even though Float.NaN==Float.NaNhas the value false.If <code>f1 represents +0.0f whilef2 represents -0.0f, or vice
versa, the equal test has the valuefalse, even though 0.0f==-0.0f
has the value true.

型判定にはequals()のgetClassを使用します

equals()メソッドをオーバーライドするときは、instanceofの代わりに型判定にgetClassを使用することが一般的に推奨されます。誰もが知っているように、instanceof の機能は、左側のオブジェクトが右側のクラスのインスタンスであるかどうかを判断し、ブール型データを返すことです。これは、継承内のサブクラスのインスタンスが親クラスの実装であるかどうかを判断するために使用できます。次の文に注目してください。継承内のサブクラスのインスタンスが親クラスの実装であるかどうかを判断するために使用できます。問題の原因はこの文です。まずは次の例を見てみましょう(『高品質コード: Java プログラムを改善するための 151 の提案』より抜粋)。

親クラス: person

public class Person {    
protected String name;    
public String getName() {        
return name;
    }    
    public void setName(String name) {        
    this.name = name;
    }    
    public Person(String name){        
    this.name = name;
    }    
    public boolean equals(Object object){        
    if(object instanceof Person){
            Person p = (Person) object;            
            if(p.getName() == null || name == null){                
            return false;
            }            
            else{                
            return name.equalsIgnoreCase(p.getName());
            }
        }        
        return false;
    }
}

サブクラス: Employee

public class Employee extends Person{    private int id;
    
    public int getId() {        
    return id;
    }

    public void setId(int id) {        
    this.id = id;
    }

    public Employee(String name,int id){        
    super(name);        
    this.id = id;
    }    
    /**
     * 重写equals()方法
     */
    public boolean equals(Object object){        
    if(object instanceof Employee){            
    Employee e = (Employee) object;            
    return super.equals(object) && e.getId() == id;
        }        
        return false;
    }
}

上記の親クラス person とサブクラス Employee は両方とも、equals() を書き換えますが、Employee には親クラスよりも 1 つ多い id 属性があります。テストプログラムは次のとおりです。

public class Test {    public static void main(String[] args) {
        Employee e1 = new Employee("chenssy", 23);
        Employee e2 = new Employee("chenssy", 24);
        Person p1 = new Person("chenssy");
        
        System.out.println(p1.equals(e1));
        System.out.println(p1.equals(e2));
        System.out.println(e1.equals(e2));
    }
}

上記は 2 人の従業員と一般人を定義していますが、名前は同じですが、それらは間違いなく同一人物ではないため、論理的には出力結果はすべて false になるはずですが、それが裏目に出て、結果は: true、true、false です。


名前を比較するだけでなく ID も比較する必要があるため、e1!=e2 であることを理解するのは非常に簡単です。しかし、p1 は e1 と e2 の両方に等しいので、e1 と e2 は明らかに 2 つの異なるクラスであるため、これは非常に奇妙です。なぜこのようなことが起こるのでしょうか。まず、p1.equals(e1) は p1 の equals メソッドを呼び出します。このメソッドは、instanceof キーワードを使用して、e1 が Person クラスであるかどうかを確認します。ここでは、instanceof: を見て、左側のオブジェクトがクラスのインスタンスであるかどうかを判断します。右側では、継承内のサブクラスのインスタンスが親クラスの実装であるかどうかを判断するために使用することもできます。それらの間には継承関係があるため、必ず true が返され、名前が同じであるため、結果は必ず true になります。


つまり、上記の状況は、「悪用」するのが非常に簡単なキーワード、instanceof が使用されているために発生します。したがって、equals をオーバーライドする場合は、型判定に getClass を使用することを推奨します。代わりに、instanceof を使用してください。


上記は、Java の改善に関する章の概要です ----equals() メソッドの詳細については、PHP 中国語 Web サイト (www.php.cn) に注目してください。


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。