ホームページ >Java >&#&チュートリアル >Java で等号をオーバーライドするより詳細なメソッドの概要
最近、私は同僚とイコールと == の違いについて話していました。これは実際には非常に古くて単純な質問ですが、equals メソッドを自分でオーバーライドしたい場合、知らないことはあっても知っておく必要があることがいくつかあることがわかります。同等の内容をカバーするには多大な注意が必要です。 Object は非常に特殊なクラスですが、その主な役割は拡張することです。その非最終メソッドにはすべて、明確な 普遍的な規約 があります。これらはメソッドをオーバーライドするように設計されているためです。 equals、hashCode、toString、clone、およびfinalizeをオーバーライドするクラスは、これらのメソッドの一般的な規則に準拠する必要があります。これができないと、複数のクラスを組み合わせたときに望ましい効果を達成することが困難になります。
equals メソッドをオーバーライドするのは簡単そうに見えますが、エラーを引き起こす可能性のあるオーバーライド メソッドが多数あります。このエラーを回避する最も簡単な方法は、equals をオーバーライドしないことです。この場合、各クラス インスタンスはそれ自体とのみ等しくなります。では、どのような状況で、equals メソッドをオーバーライドしないことを選択できるのでしょうか?
クラスの各インスタンスは本質的に一意です
これは、各スレッド インスタンスなど、値ではなくアクティブなエンティティを表すクラスに当てはまります。各スレッドは一意であるため、equals メソッドと比較することは無意味です。この場合、Object クラスの equals で完全に十分であるため、equals メソッドをオーバーライドする必要はありません。
オブジェクトクラスでのequalsメソッドの実装:
public boolean equals(Object obj) { return (this == obj); }
クラスが論理的等価判定を必要とするかどうかは気にしません
一部のクラスは「数値クラス」であり、サイズの比較と数学的演算は次の仕事です。これらのクラス。この場合、クラスに格納されている値を比較し、論理的等しいかどうかを判断する必要があります。クラスに加えて、ほとんどのクラスには「一方が他方と等しいかどうか」という概念がありません。論理的等価性を考慮しないこのようなクラスは、equals メソッドをオーバーライドする必要はありません。
スーパークラスで実装されたequalsはサブクラスにも適用できます
例えば、AbstractSetクラスを継承したHashSetクラスのequalsメソッドに違いはなく、HashSetはAbstractSetのequalsメソッドを直接利用することができます。
上記とは逆に、equals メソッドをオーバーライドする必要がある状況は次のとおりです。クラスに独自の論理的等価性の概念があり、親クラスに利用可能な equals メソッドのオーバーライドがない場合。現時点では、自分たちでカバーする必要があります。
equalsメソッドは同値関係を実装します。離散数学における同値関係の概念を学びました。R 上の二項関係は、自発対称性と推移性を満たす場合、それは等価です。等しい値とこれら 3 つのプロパティの関係を詳しく分析してみましょう。
反射性: null 以外の参照値 x に対して、x.equals(x) は true を返さなければなりません
対称性: null 以外の参照値 x および y について、y が等しい場合にのみ ( x) は true を返します。x.equals(y) は true を返す必要があります
推移性: null 以外の参照値 x、y、z について、x.equals(y) が true を返す場合、y.equals ( z) も true を返す場合、x.equals(z) は true を返す必要があります。
反射性: ∀ a ∈A, => (a, a) ∈ R
対称性: (a, b) ∈R∧ a ≠ b => (b, a)∈R
推移性: (a, b) )∈R, (b, c)∈R =>(a, c)∈R
この3つの性質を比較してみても問題ありません。等価メソッドは同値関係を実現していることがわかります。
オブジェクトのequalsメソッドはアドレスを調べるだけですが、これでは明らかに要件を満たすことができません。では、equals メソッドを自分で作成する場合、高品質で論理的な比較メソッドを作成するにはどうすればよいでしょうか?等しいの記述は、次の 4 つのステップに要約できます:
1. == 演算子を使用して、パラメーターがオブジェクトへの単なる参照であるかどうかを確認します
結果が等しい場合は、x を示す true が返されます。と y はオブジェクトへの異なる参照であり、判断する必要はありません。
2. パラメータの型が正しいかどうかを確認するには、instanceof 演算子を使用します 結果が正しい型ではない場合は、false を返します。equals メソッドは Object クラスから継承するため、パラメータの型を回避することはできません。まず、instanceof を使用してパラメータのタイプを決定します。タイプが正しくない場合は、次のステップに進む必要はありません。
3. パラメータを正しい型に変換します 検出は以前に行われているため、このステップでの型変換は問題ありません。
4. 各クラスで論理的に比較する必要があるドメイン値を判断します x と y が同じ型の異なるインスタンスであることを確認し、判断する必要があるドメイン値を取り出すだけです論理比較を行い、比較判定を行います。すべてが正しい場合は true を返し、そうでない場合は false を返します。
equalsメソッドを書いた後は、再帰性、対称性、推移性を満たしているかどうかを繰り返し判断する必要があります。それだけではなく、平等性を確保しながらequalsメソッドを記述する際に注意すべき点がいくつかあり、これを改善する必要があります。
equalsメソッドをオーバーライドするときは必ずhashCodeメソッドをオーバーライドする
ハッシュ関連のクラスを書く場合は、equalsメソッドをオーバーライドするときにhashCodeメソッドもオーバーライドする必要があります。ハッシュ テーブルでは、論理的に同一のオブジェクトは同じハッシュ コードを持つ必要があるためです。比較的単純な例を挙げると、HashSet に String を格納します。== を使用すると、同じ内容を持つ 2 つの String 文字列が false と判断される可能性がありますが、HashSet にはそれらのコピーが 1 つだけ存在します。これは、同じロジックの String は同じ hashCode を持つためです。
一般に、クラスのequalsメソッドをオーバーライドすると、特定の状況下では2つの異なるオブジェクトが論理的に等しいことが証明されます。現時点でハッシュに関連している場合、2 つのオブジェクトには同じ hashCode が必要です。したがって、equals メソッドをオーバーライドする場合は、必ず hashCode メソッドをオーバーライドしてください。
equalsメソッドをあまりスマートにしないでください
上記の実装手順に従ってequalsメソッドを書くだけであれば、規定に準拠しており、変なエラーは発生しません。しかし、さまざまな派手な等価関係を追求することに固執してコードを肥大化させると、本来の凝集性の高さという意図に反するだけでなく、コード内に不可解なエラーが発生することがあります。
equals メソッドのパラメータの型を間違えないでください
言うとおかしいと思うかもしれませんが、これが実際に起こることです。パラメーターの型を変更した後、equals メソッドは Object クラスとは何の関係もなくなるため、コンパイラーはエラーを報告しなくなり、プログラマーにとっては終わりのない頭痛の種だけが残ります。パラメーターの型がオブジェクトであることに気づかないと、プログラムがなぜ正しく動作しないのか考えて何時間も費やすことになるでしょう。
最近、私は同僚とイコールと == の違いについて話していました。これは実際には非常に古くて単純な質問ですが、equals メソッドを自分でオーバーライドしたい場合、知らないことはあっても知っておく必要があることがいくつかあることがわかります。同等の内容をカバーするには多大な注意が必要です。 Object は非常に特殊なクラスですが、その主な役割は拡張することです。その非最終メソッドにはすべて、明確な 普遍的な規約 があります。これらはメソッドをオーバーライドするように設計されているためです。 equals、hashCode、toString、clone、およびfinalizeをオーバーライドするクラスは、これらのメソッドの一般的な規則に準拠する必要があります。これができないと、複数のクラスを組み合わせたときに望ましい効果を達成することが困難になります。
equals メソッドをオーバーライドするのは簡単そうに見えますが、エラーを引き起こす可能性のあるオーバーライド メソッドが多数あります。このエラーを回避する最も簡単な方法は、equals をオーバーライドしないことです。この場合、各クラス インスタンスはそれ自体とのみ等しくなります。では、どのような状況で、equals メソッドをオーバーライドしないことを選択できるのでしょうか?
クラスの各インスタンスは本質的に一意です
これは、各スレッド インスタンスなど、値ではなくアクティブなエンティティを表すクラスに当てはまります。各スレッドは一意であるため、equals メソッドと比較することは無意味です。この場合、Object クラスの equals で完全に十分であるため、equals メソッドをオーバーライドする必要はありません。
オブジェクトクラスでのequalsメソッドの実装:
public boolean equals(Object obj) { return (this == obj); }
クラスが論理的等価判定を必要とするかどうかは気にしません
一部のクラスは「数値クラス」であり、サイズの比較と数学的演算は次の仕事です。これらのクラス。この場合、クラスに格納されている値を比較し、論理的等しいかどうかを判断する必要があります。クラスに加えて、ほとんどのクラスには「一方が他方と等しいかどうか」という概念がありません。論理的等価性を考慮しないこのようなクラスは、equals メソッドをオーバーライドする必要はありません。
スーパークラスで実装されたequalsはサブクラスにも適用できます
例えば、AbstractSetクラスを継承したHashSetクラスのequalsメソッドに違いはなく、HashSetはAbstractSetのequalsメソッドを直接利用することができます。
上記とは逆に、equals メソッドをオーバーライドする必要がある状況は次のとおりです。クラスに独自の論理的等価性の概念があり、親クラスに利用可能な equals メソッドのオーバーライドがない場合。現時点では、自分たちでカバーする必要があります。
equalsメソッドは同値関係を実装します。離散数学における同値関係の概念を学びました。R 上の二項関係は、自発対称性と推移性を満たす場合、それは等価です。等しい値とこれら 3 つのプロパティの関係を詳しく分析してみましょう。
反射性: null 以外の参照値 x に対して、x.equals(x) は true を返さなければなりません
対称性: null 以外の参照値 x および y について、y が等しい場合にのみ ( x) は true を返します。x.equals(y) は true を返す必要があります
推移性: null 以外の参照値 x、y、z について、x.equals(y) が true を返す場合、y.equals ( z) も true を返す場合、x.equals(z) は true を返す必要があります。
反射性: ∀ a ∈A, => (a, a) ∈ R
対称性: (a, b) ∈R∧ a ≠ b => (b, a)∈R
推移性: (a, b) )∈R, (b, c)∈R =>(a, c)∈R
この3つの性質を比較してみても問題ありません。等価メソッドは同値関係を実現していることがわかります。
オブジェクトのequalsメソッドはアドレスを調べるだけですが、これでは明らかに要件を満たすことができません。では、equals メソッドを自分で作成する場合、高品質で論理的な比較メソッドを作成するにはどうすればよいでしょうか?等しいの記述は、次の 4 つのステップに要約できます:
1. == 演算子を使用して、パラメーターがオブジェクトへの単なる参照であるかどうかを確認します
結果が等しい場合は、x を示す true が返されます。と y はオブジェクトへの異なる参照であり、判断する必要はありません。
2. パラメータの型が正しいかどうかを確認するには、instanceof 演算子を使用します 結果が正しい型ではない場合は、false を返します。equals メソッドは Object クラスから継承するため、パラメータの型を回避することはできません。まず、instanceof を使用してパラメータのタイプを決定します。タイプが正しくない場合は、次のステップに進む必要はありません。
3. パラメータを正しい型に変換します 検出は以前に行われているため、このステップでの型変換は問題ありません。
4. 各クラスで論理的に比較する必要があるドメイン値を判断します x と y が同じ型の異なるインスタンスであることを確認し、判断する必要があるドメイン値を取り出すだけです論理比較を行い、比較判定を行います。すべてが正しい場合は true を返し、そうでない場合は false を返します。
equalsメソッドを書いた後は、再帰性、対称性、推移性を満たしているかどうかを繰り返し判断する必要があります。それだけではなく、平等性を確保しながらequalsメソッドを記述する際に注意すべき点がいくつかあり、これを改善する必要があります。
equalsメソッドをオーバーライドするときは必ずhashCodeメソッドをオーバーライドする
ハッシュ関連のクラスを書く場合は、equalsメソッドをオーバーライドするときにhashCodeメソッドもオーバーライドする必要があります。ハッシュ テーブルでは、論理的に同一のオブジェクトは同じハッシュ コードを持つ必要があるためです。比較的単純な例を挙げると、HashSet に String を格納します。== を使用すると、同じ内容を持つ 2 つの String 文字列が false と判断される可能性がありますが、HashSet にはそれらのコピーが 1 つだけ存在します。これは、同じロジックの String は同じ hashCode を持つためです。
一般に、クラスのequalsメソッドをオーバーライドすると、特定の状況下では2つの異なるオブジェクトが論理的に等しいことが証明されます。現時点でハッシュに関連している場合、2 つのオブジェクトには同じ hashCode が必要です。したがって、equals メソッドをオーバーライドする場合は、必ず hashCode メソッドをオーバーライドしてください。
equalsメソッドをあまりスマートにしないでください
上記の実装手順に従ってequalsメソッドを書くだけであれば、規定に準拠しており、変なエラーは発生しません。しかし、さまざまな派手な等価関係を追求することに固執してコードを肥大化させると、本来の凝集性の高さという意図に反するだけでなく、コード内に不可解なエラーが発生することがあります。
equals メソッドのパラメータの型を間違えないでください
言うとおかしいと思うかもしれませんが、これが実際に起こることです。パラメーターの型を変更した後、equals メソッドは Object クラスとは何の関係もなくなるため、コンパイラーはエラーを報告しなくなり、プログラマーにとっては終わりのない頭痛の種だけが残ります。パラメーターの型がオブジェクトであることに気づかないと、プログラムがなぜ正しく動作しないのか考えて何時間も費やすことになるでしょう。
以上がJava で等号をオーバーライドするより詳細なメソッドの概要の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。