web-dev-qa-db-ja.com

コンパレータ:メソッド機能と同等

実際、私は、コンパレータインターフェイスを実装する必要があるときに、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メソッドの機能性の概念をクリアできるなら

6

Comparatorequals()メソッドを実装すると、あるコンパレータが別のコンパレータと同じ順序を提供することを示すことができます。要素の並べ替え方法とは関係ありません。これは非常に高度で、ほとんど必要とされない機能です。コンパレータのequals()メソッドが実際に呼び出される状況に遭遇する可能性はほとんどありません。無視することをお勧めします。

7
Mike Nakis

クラスの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についてですが、組み込みの型を使用する代わりに、独自の型を導入すると、そのロジックを理解しやすくなります。

たとえば、Appleweightの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のいずれかを指定する必要があります。

今あなたの質問に関して:Comparatorequals()メソッドの間に関係はありません。 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()と一致しないことを意味します。

4
fg78nc

Comparatorメソッドとequals()メソッドをリンクしている理由がわかりません。 interfacesComparableのような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が表示されます。これは、コレクションTreeSetPeronクラスのどの属性で混乱しているのかという理由からです。並べ替えを行います。ここで、interfacesComparableのような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()メソッドは、重複を見つけるのに役立ちます。これがお役に立てば幸いです。

1
Arun Sudhakaran

オーバーライドしたequals()メソッドは_MyComparator class_にあるため、Mycomparatorの2つのインスタンスを比較する必要がある場合に使用されます;)

そして、それはあなたがしていることではありません、あなたはintを比較しているので、そうですcompare()メソッドはsortingTreesetに使用されるので便利ですが、ここでのequalsメソッドは使用されません

99%の確率で、implementsComparatorのクラスで_override equals_メソッドを実行する必要はありません。これは、これらがcompare値に対してのみ存在し、他の値に対してではなく、実際、ほとんどの場合、属性の場合、comparatorが等しくなることはありません。

1
azro

Equalsメソッドは、2つのコンパレータの同等性をチェックするために使用されます。つまり、equalsメソッドでは、ComparatorAとComparatorBを同一にするものを指定できます。これらのコンパレータを使用してソートされる要素とは関係ありません。

0
Hitesh