実際、私は、コンパレータインターフェイスを実装する必要があるときに、equalsメソッドをオーバーライドできると述べたチュートリアルの1つを実行しています(ただし、オーバーライドする必要はありません)。
だからもっとよく理解するために
私は以下のようにメソッドをオーバーライドします
Test.Java
import Java.util.TreeSet;
public class Test
{
public static void main(String[] args)
{
TreeSet t = new TreeSet(new MyComparator());
t.add(1);
t.add(1);
t.add(2);
System.out.println(t);
}
}
MyComparator.Java
java.util.Comparatorをインポートします。
public class MyComparator
implements Comparator
{
@Override
public int compare(Object o1, Object o2)
{
Integer i1 = (Integer) o1;
Integer i2 = (Integer) o2;
return i1.compareTo(i2);
}
@Override
public boolean equals(Object o1)
{
return false;
}
}
他のシナリオの場合
import Java.util.Comparator;
public class MyComparator
implements Comparator
{
@Override
public int compare(Object o1, Object o2)
{
Integer i1 = (Integer) o1;
Integer i2 = (Integer) o2;
return i1.compareTo(i2);
}
@Override
public boolean equals(Object o1)
{
return true;
}
}
これで、equalsメソッドからtrueまたはfalseのどちらから何を返すかに関係なく、同じツリーセット値を返します。誰かがequalsメソッドの機能性の概念をクリアできるなら
Comparator
にequals()
メソッドを実装すると、あるコンパレータが別のコンパレータと同じ順序を提供することを示すことができます。要素の並べ替え方法とは関係ありません。これは非常に高度で、ほとんど必要とされない機能です。コンパレータのequals()
メソッドが実際に呼び出される状況に遭遇する可能性はほとんどありません。無視することをお勧めします。
クラスのequals()
メソッド、Comparator
およびComparator
は、一部のJavaコレクションクラスがcompareTo()
メソッドとequals()
メソッドが一貫した結果を返していません。
Javaは==演算子を使用して、2つのプリミティブを比較したり、2つの変数が同じオブジェクトを参照しているかどうかを確認したりします。例:
_String Apple1 = new String("Apple");
String Apple2 = new String("Apple");
System.out.println(Apple1.equals(Apple2)); // true
StringBuilder app1 = new StringBuilder("Apple");
StringBuilder app2 = new StringBuilder("Apple");
System.out.println(app1.equals(app2)); // false
_
ご覧のとおり、さまざまな動作が発生します。何故ですか?これは、Stringクラスがequals()メソッドを実装し、値が同じであることを確認するために発生します。一方、StringBuilderはequals()メソッドを実装せず、代わりにObject
クラスによって提供されるequals()の実装を使用します。また、Object
クラスによって提供(継承)される実装は、参照される2つのオブジェクトが同じであるかどうかを単にチェックするだけです。
したがって、2つのオブジェクトが同等であるかどうかを確認するにはJavaはequals()
メソッドを使用し、独自の型を導入する場合は常にequals()
メソッドをオーバーライドする必要があります。 equals()
メソッドのObject
クラス実装に依存したい
たとえば、私たち自身のタイプを紹介しましょう:単純なクラスApple
_public class Apple {
private int weight;
private int cost;
private String color;
_
では、2つのリンゴが等しいかどうかをどのように判断しますか?色、重量、価格などで?これが、独自のequalsメソッドを明示的に指定する必要がある理由です。これにより、タイプのオブジェクトが等しいかどうかを比較できます。
以下の例では、2つのApple
オブジェクトが等しいかどうかを比較し、2つのオブジェクトが同じ「Apple」クラスに属し、重量とコストが同じである場合、2つのオブジェクトが等しいことを示しています。色で比較していないことに注意してください。この場合、色は無関係であると想定しています。つまり、同じ重量で同じコストの異なる色のリンゴは等しいと見なされるという事実を受け入れます。
_ @Override
public boolean equals(Object obj) {
if ( !(obj instanceof Apple)) return false;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Apple other = (Apple) obj;
if (cost != other.cost and weight != other.weight )
return false;
return true;
}
_
equals()
メソッドには任意のロジックを実装できます。 Java equals()
メソッドは非常に重要であり、開発者が従うべきコントラクトまたは重要なルールを提供します。リストしません。 ここ から取得します。 、それらは論理的で非常に単純です。
equals()
の別のコントラクトがあります-equals()
をオーバーライドするときはいつでも、hashCode()
メソッドをオーバーライドすることも期待されます。その背後にある理由は、オブジェクトがマップにキーとして格納されている場合、ハッシュコードが一部のJavaコレクションによって内部的に使用されるためです。
ハッシュコードは、オブジェクトをカテゴリに分類する番号です。さまざまな種類のリンゴ(赤、緑、黄色)が与えられ、特定の種類を求められたときにそれらを返すように求められたと想像してください。それらを分類し、それに応じてそれぞれを異なるバケットに入れ、特定の並べ替えを要求されたときはいつでも(簡単にするために赤いリンゴとしましょう)、すでに並べ替えて分類しているので、はるかに高速に取得できます。 。なぜhashcode()
を実装する必要があるのかが明確になったことを願っています。 hashcode()
には、equals()
メソッドと同じ独自のコントラクトまたはルールがあります。彼らはほとんど常識的です:
まず、同じプログラム内のhashcode()
の結果は変更されません。 hascode()
の計算に、プログラムの実行中に変更する変数を含めないでください。たとえば、Appleのコストが変更可能である場合、つまり変更される可能性がある場合、それらをhashcode()計算に含めることはお勧めできません。そうしないと、結果に一貫性がなくなります。
2番目のルールは、2つのオブジェクトで呼び出されたときに、equals()
がtrueを返す場合、それらの各オブジェクトでhashCode()
を呼び出すと同じ結果を取得する必要があることを示しています。ただし、2つのオブジェクトで呼び出されたときにequals()
がfalseを返す場合、これらの各オブジェクトでhashCode()
を呼び出すと、異なる結果を返す必要はありません。紛らわしい?どうして? hashCode()
の結果は、等しくないオブジェクトで呼び出されたときに一意である必要はないため、2つの等しくないオブジェクトを1つのバケットに入れることができます。
Comparator
についてですが、組み込みの型を使用する代わりに、独自の型を導入すると、そのロジックを理解しやすくなります。
たとえば、Apple
とweight
の2つの属性を持つクラスprice
があり、このタイプのオブジェクトを並べ替えられたコレクションTreeSet
に出力するとします。
_public class Apple {
private int weight;
private int cost;
_
では、このリンゴをコレクション内でどのように並べ替えますか?weight
またはprice
で並べ替えますか?コンパイラはどのように決定しますか?
適切なComparator
またはComparable
を指定すると、意図を渡すことができます。コレクションにオブジェクトを追加してみましょう。
_ public class Apple {
private int weight;
private int cost;
public static void main(String[] args) {
Apple redApple = new Apple();
redApple.setCost(10);
redApple.setWeight(2);
Apple greenApple = new Apple();
greenApple.setCost(12);
greenApple.setWeight(3);
Set<Apple> apples = new TreeSet<>();
apples.add(redApple);
apples.add(greenApple);
System.out.println(apples);
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public int getCost() {
return cost;
}
public void setCost(int cost) {
this.cost = cost;
}
@Override
public String toString() {
return "Apple [weight=" + weight + ", cost=" + cost + "]";
}
}
_
上記のコードを実行すると、RuntimeError:_Apple cannot be cast to Java.lang.Comparable
_が発生します。これは、コンパイラがリンゴをどのように比較するかを判断する必要があるためです。それでは修正しましょう:Comparable
インターフェースを実装しましょう
_ public class Apple implements Comparable<Apple> {
_
compareTo
メソッドをオーバーライドします
_ @Override
public int compareTo(Object obj) {
int cost = ((Apple) obj).getCost();
return this.getCost() - cost; // sorting in ascending order.
// change to this to sort in Descending order
// return cost - this.getCost();
}
_
この変更を加えて、コードを実行してみましょう。
_[Apple [weight=2, cost=10], Apple [weight=3, cost=12]]
_
私たちのコレクションは、コストの昇順で並べ替えられています。
Apple
クラスにアクセスできず、ソースコードを変更してComparable
を実装できない場合はどうでしょうか。
これはComparator
が役立つところです。
このクラスは変更できないと想定しているため、_implements Comparable
_を削除します
_public class Apple {
_
メソッドを削除します
_@Override
public String toString() {
return "Apple [weight=" + weight + ", cost=" + cost + "]";
}
_
コンパレータ実装の追加:
_ public class AppleComparator implements Comparator<Apple> {
@Override
public int compare(Apple app1, Apple app2) {
return app1.getCost() - app2.getCost();
}
}
_
これで、コレクションにComparator
を指定して、自分の意図を表現できます。
_Set<Apple> apples = new TreeSet<>(new AppleComparator());
_
コレクションは、提供されたコンパレータに応じて、コストでソートされます。したがって、コレクション、特にComparator
に格納するには、Comparable
またはTreeSet
のいずれかを指定する必要があります。
今あなたの質問に関して:Comparator
とequals()
メソッドの間に関係はありません。 Comparable
(compareTo()メソッド)とequals()
メソッドの間には必要な一貫性のみがあります。
例-上記のApple
クラスでは、Comparableを実装するバージョンで、同等性を判断するための新しいロジックを導入しています。 compareTo()
メソッドは2つのオブジェクトが等しい場合は0を返し、equals()
メソッドは2つのオブジェクトが等しい場合はtrueを返します。
X.compareTo(y)が0に等しい場合は常に、x.equals(y)が真である場合に等しいと一致する必要があるcompareTo()
を使用する自然順序付け。したがって、Comparable
クラスを作成する必要があります。 compareTo()
メソッドとequals()
メソッドが一貫した結果を返さない場合、一部のJavaコレクションクラスが予期しない動作をする可能性があるため、equalsと一致します。
次の例は、equalsと一致しないcompareTo()メソッドを示しています。
_public class Apple implements Comparable<Apple> {
private int weight;
private int cost;
private String color;
public boolean equals(Object obj) {
if(!(obj instanceof Apple)) {
return false;
}
Apple other = (Apple) obj;
return this.weight == other.weight;
}
public int compareTo(Apple obj) {
return this.cost.compareTo(obj.cost); }
}
_
Appleオブジェクトをコストで並べ替えたいが、コストが一意でない場合があります。同じコストのオブジェクトが2つある可能性があるため、compareTo()
の戻り値はそうではない可能性があります。 2つの等しいApple
オブジェクトを比較する場合は0になります。これは、このcompareTo()
メソッドがequals()
と一致しないことを意味します。
Comparator
メソッドとequals()
メソッドをリンクしている理由がわかりません。 interfaces
やComparable
のようなComparator
は、sorting purpose
用に設計されたcollection
にデータを入れる場合のように、比較メカニズムを提供するために使用されます。比較メカニズムが必要です。これが例です
package snippet;
import Java.util.Iterator;
import Java.util.Set;
import Java.util.TreeSet;
class Person {
private int id;
private String name;
private String code;
private double salary;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public boolean equals(Object obj) {
if(obj != null && (obj instanceof Person)) {
Person other = (Person) obj;
return this.code.equals(other.getCode());
}
return false;
}
public Person(int id, String name, String code, double salary) {
super();
this.id = id;
this.name = name;
this.code = code;
this.salary = salary;
}
}
public class EqualsMethodImpl
{
public static void main(String[] args) {
Set<Person> set = new TreeSet<Person>();
Person p1 = new Person(1, "Sam", "M-1-SAM-50", 50000.00);
Person p2 = new Person(2, "Diaz", "M-1-SAM-35", 35000.00);
Person p3 = new Person(3, "Remy", "M-1-SAM-100", 100000.00);
Person p4 = new Person(4, "Cesar", "M-1-SAM-80", 80000.00);
Person p5 = new Person(5, "Rino", "M-1-SAM-5", 5000.00);
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
set.add(p5);
printPersons(set);
}
private static void printPersons(Set<Person> set) {
System.out.println("Id\tName\tCode\t\tSalary");
Iterator<Person> perItr = set.iterator();
while(perItr.hasNext()) {
Person p = perItr.next();
System.out.println(p.getId()+"\t"+p.getName()+"\t"+p.getCode()+"\t"+p.getSalary());
}
}
}
このコードを実行している間、行set.add(p1);
にClasCastException
が表示されます。これは、コレクションTreeSet
がPeron
クラスのどの属性で混乱しているのかという理由からです。並べ替えを行います。ここで、interfaces
やComparable
のようなComparator
が重要になります。
このコードをPerson
クラスに追加します
public int compareTo(Person other) {
Double person1Salary = this.getSalary();
Double person2Salary = other.getSalary();
return person1Salary.compareTo(person2Salary);
}
クラスをPerson implements Comparable<Person>
のような比較可能なタイプにすることによって
したがって、このコードでは、並べ替えを行う必要がある属性のコレクションについて説明しています。したがって、Set
のコンテンツを印刷すると、基本給に基づいて注文されます(デフォルトでは昇順)。
Byte, Short, Integer, Long, Float, Double
のようなラッパークラスとString
のような他の事前定義されたクラスはすべてComaparable
インターフェイスを実装しているため、Sortableコレクションに渡すことができます。
equals
メソッドについては、2つのオブジェクトの同等性をチェックするために使用されます。Objectクラスから継承された従来のequals
メソッドは、アドレスの場所に基づいて同等性をチェックします。したがって、Personクラスで、equals
メソッドをオーバーライドしておらず、次のようなコードを記述している場合を考えてみましょう。
Person p1 = new Person(1, "Sam", "M-1-SAM-50", 50000.00);
Person p2 = new Person(1, "Sam", "M-1-SAM-50", 50000.00);
System.out.println(p1.equals(p2));
どちらも2つの異なる住所の場所に配置された2つの異なるオブジェクトであるため、falseが返されますが、オブジェクトには同じ人物のデータがあることがわかっています。これは、Person code
に基づいてPerson
クラスで行ったようにequals()
メソッドをオーバーライドする場所です。その場合、コードが等しいため、System.out.println(p1.equals(p2));
はtrueを出力します。 equals()
メソッドは、重複を見つけるのに役立ちます。これがお役に立てば幸いです。
オーバーライドしたequals()
メソッドは_MyComparator class
_にあるため、Mycomparator
の2つのインスタンスを比較する必要がある場合に使用されます;)
そして、それはあなたがしていることではありません、あなたはint
を比較しているので、そうですcompare()
メソッドはsorting
Treeset
に使用されるので便利ですが、ここでのequalsメソッドは使用されません
99%の確率で、implements
Comparator
のクラスで_override equals
_メソッドを実行する必要はありません。これは、これらがcompare
値に対してのみ存在し、他の値に対してではなく、実際、ほとんどの場合、属性の場合、comparator
が等しくなることはありません。
Equalsメソッドは、2つのコンパレータの同等性をチェックするために使用されます。つまり、equalsメソッドでは、ComparatorAとComparatorBを同一にするものを指定できます。これらのコンパレータを使用してソートされる要素とは関係ありません。