CodeGym /Java Blog /ランダム /JavaのComparatorクラス
John Squirrels
レベル 41
San Francisco

JavaのComparatorクラス

ランダム グループに公開済み
やあ!今日はオブジェクトの比較について話します。 Java の Comparator クラス - 1 うーん...でも、この話題についてはすでに何度か話したことはありませんか? :/演算子とメソッドが==どのように機能するかはわかっています。比較すると少し違います。以前は、おそらく「オブジェクトが等しいかどうかをチェックする」ことを意味していました。しかし、オブジェクトを相互に比較する理由はまったく異なる場合があります。これらの中で最も明白なのは並べ替えです。数値または文字列を並べ替えるように言われた場合、問題なくこれを処理できると思います。 equals()hashCode()ArrayList<>

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       String name1 = "Masha";
       String name2 = "Sasha";
       String name3 = "Dasha";

       List<String> names = new ArrayList<>();
       names.add(name1);
       names.add(name2);
       names.add(name3);

       Collections.sort(names);
       System.out.println(names);
   }
}
コンソール出力:

[Dasha, Masha, Sasha]
Collectionsクラスとそのメソッド を覚えていればsort()、成功です! 数字にも困らないと思います。ここでは、さらに難しいタスクを紹介します。

public class Car {
  
   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }
  
   // ...getters, setters, toString()
  
}

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);
      
       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);
   }
}
タスクは実際には簡単です。Car1 つのクラスと 3 つの Car オブジェクトがあります。リスト内の車を並べ替えていただけますか。おそらく「どのように分類すればよいのですか?」と疑問に思うでしょう。名前で?製造年別でしょうか?最高速で?素晴らしい質問です。現時点では、Carオブジェクトを並べ替える方法がわかりません。そして当然のことですが、Java もそれを知りません。Carオブジェクトのリストをメソッドに渡そうとするとCollections.sort()、エラーが発生します。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(20012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       // Compilation error!
       Collections.sort(cars);
   }
}
実際、言語は、作成したクラスのオブジェクトを並べ替える方法をどのようにして知るのでしょうか? これはプログラムが何を行う必要があるかによって異なります。これらのオブジェクトを比較するように Java に何らかの方法で教えなければなりません。そして、私たちが望むようにそれらを比較します。Java には、このための特別なメカニズム、つまりComparableインターフェイスがあります。何らかの方法でオブジェクトを比較および並べ替えるためにCar、クラスは次の 1 つのメソッドで構成されるこのインターフェイスを実装する必要がありますcompareTo()

public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return 0;
   }

   // ...getters, setters, toString()

}
ご注意くださいComparable<Car>だけではなくインターフェイスを指定したことを確認しますComparable。これはパラメータ化されたインターフェイスです。つまり、特定の関連クラスを指定する必要があります。<Car>原則として、インターフェイスから削除できますが、その場合Object、デフォルトでは比較がオブジェクトに基づいて行われます。メソッドの代わりにcompareTo(Car o)、クラスには次のものがあります。

@Override
   public int compareTo(Object o) {
       return 0;
   }
もちろん、 を使用する方がはるかに簡単ですCar。メソッド内にcompareTo()、車を比較するためのロジックを実装します。製造年ごとに並べ替える必要があるとします。おそらく、メソッドがではなくcompareTo()を返すことに気づいたでしょう。驚かないでください。2 つのオブジェクトを比較する場合、次の 3 つの可能性があります。 intboolean
  • а < b
  • a > b
  • a == b
boolean値は true と false の 2 つだけなので、オブジェクトの比較には適していません。を使用するとint、すべてがはるかに簡単になります。戻り値が の場合> 0a > b。の結果が の場合compareTo< 0ですa < b。そして、結果が の場合== 0、2 つのオブジェクトは等しいことになりますa == b。車を製造年ごとに分類するようにクラスに教えるのは簡単です。

@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
しかし、ここで何が起こっているのでしょうか?1 つの Car オブジェクト ( ) を取得しthis、この車の製造年を取得し、そこから別の車 (オブジェクトが比較されているもの) の製造年を減算します。最初の車の製造年の方が大きい場合、メソッドは を返しますint > 0this car >これは車という意味ですo。逆に、2 番目の車 ( о) の製造年の方が大きい場合、メソッドは負の数を返します。これは、 を意味しますo > this。最後に、それらが等しい場合、メソッドは を返します0。オブジェクトのコレクションを並べ替えるには、この単純なメカニズムですでに十分ですCar。他に何もする必要はありません。見てみな:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       // There was previously an error here
       Collections.sort(cars);
       System.out.println(cars);
   }
}
コンソール出力:

[Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310}, 
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}, 
Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}]
車は思い通りに並べられています!:) Java の Comparator クラス - 2いつ使用すればよいですかComparable? で実装された比較方法は、Comparable自然順序付けと呼ばれます。これは、メソッド内で、compareTo()このクラスのオブジェクトを比較する最も一般的または自然な方法を定義するためです。Java にはすでに自然な順序が備わっています。たとえば、Java は、文字列はほとんどの場合アルファベット順にソートされ、数値は数値の増加順にソートされることを認識しています。したがって、数値または文字列のリストに対してメソッドを呼び出すとsort()、それらは並べ替えられます。私たちのプログラムが通常、自動車を製造年別に比較して並べ替える場合、インターフェイスComparable<Car>compareTo()方法。しかし、これだけでは十分ではない場合はどうすればよいでしょうか? 私たちのプログラムがそれほど単純ではないことを想像してみましょう。ほとんどの場合、車の自然な分類 (製造年ごとに実行されるように設定されています) が適しています。しかし、私たちの顧客の中には高速運転の愛好家がいることもあります。彼らが閲覧できるように車のカタログを準備している場合、車は最高速度の順に並べ替える必要があります。 Java の Comparator クラス - 3たとえば、15% の確率でこのように並べ替える必要があるとします。Carこれでは、クラスの自然な並べ替えを製造年ではなく速度に基づいて設定するには明らかに十分ではありません。しかし、顧客の 15% を無視することはできません。どうしようか?ここで、別のインターフェイスが役に立ちますComparator。と同様にComparable、これはパラメータ化されたインターフェイスです。違いは何ですか? Comparableオブジェクトを「比較可能」にし、最も自然な並べ替え順序、つまりほとんどの場合に使用される並べ替え順序を定義します。 Comparator別の「比較」インターフェイスです。Car何らかの特別な並べ替え順序を実装する必要がある場合、クラスにアクセスして のロジックを変更する必要はありませんcompareTo()。代わりに、Comparator を実装する別のクラスを作成し、必要な並べ替えを実行する方法を教えることができます。

import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {
  
   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
ご覧のとおり、私たちのものはComparator非常にシンプルです。実装する必要があるインターフェイス メソッドは 1 つだけですcompare()。2 つのオブジェクトを入力として受け取りCar、通常の方法 (減算) でそれらの最大速度を比較します。と同様にcompareTo()、 an を返しint、比較の原理は同じです。これをどうやって使うのでしょうか?それはすべて簡単です:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Car> cars = new ArrayList<>();

       Car ferrari = new Car(1990, "Ferrari 360 Spider", 310);
       Car lambo = new Car(2012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

       cars.add(ferrari);
       cars.add(bugatti);
       cars.add(lambo);

       Comparator speedComparator = new MaxSpeedCarComparator();
       Collections.sort(cars, speedComparator);

       System.out.println(cars);
   }
}
コンソール出力:

[Car{manufactureYear=2012, model='Lamborghini Gallardo', maxSpeed=290}, 
Car{manufactureYear=1990, model='Ferrari 360 Spider', maxSpeed=310}, 
Car{manufactureYear=2010, model='Bugatti Veyron', maxSpeed=350}]
Collections.sort()コンパレータ オブジェクトを作成し、それを並べ替えるリストとともにメソッド に渡すだけです。sort()メソッドがコンパレータを受け取る場合、CarクラスのcompareTo()メソッドで定義された自然な並べ替えは使用されません。代わりに、渡されたコンパレータによって定義された並べ替えアルゴリズムが適用されます。 これを行う利点は何ですか? まず、既存のコードとの互換性です。ほとんどの場合に使用される既存の並べ替え方法を維持しながら、新しい特別な並べ替え方法を作成しました。私たちはクラスにはまったく触れませんでしたCar。それは だったComparableので、そのまま残ります。

public class Car implements Comparable<Car> {

   private int manufactureYear;
   private String model;
   private int maxSpeed;

   public Car(int manufactureYear, String model, int maxSpeed) {
       this.manufactureYear = manufactureYear;
       this.model = model;
       this.maxSpeed = maxSpeed;
   }

   @Override
   public int compareTo(Car o) {
       return this.getManufactureYear() - o.getManufactureYear();
   }

   // ...getters, setters, toString()

}
2番目に、柔軟性です。並べ替えアルゴリズムは好きなだけ追加できます。たとえば、色、速度、重量、またはバットマンの映画で車が使用された回数によって車を並べ替えることができます。必要なのは、追加の を作成することだけですComparator。それでおしまい!今日は、実際のプロジェクトで頻繁に使用される 2 つの非常に重要なメカニズムを学習しました。しかし、ご存知のとおり、実践のない理論は何の役にも立ちません。知識を統合していくつかのタスクを完了しましょう。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION