JavaRush /Java Blog /Random-JA /Javaのコンパレータ

Javaのコンパレータ

Random-JA グループに公開済み
こんにちは!今日はオブジェクトの比較について話します。うーん...でも、このことについてはすでに何度か話し合っているような気がしますが?:/ 私たちは、 と メソッドだけでなく、「 」演算子がどのように機能するかを知ってい==ます。比較というのは実はそういうことではありません。以前は、「オブジェクトが等しいかどうかをテストする」ということを意味していました。ただし、オブジェクトを相互に比較すると、目的がまったく異なる場合があります。最もわかりやすいのは並べ替えです。数値や文字列のリストを並べ替えるように言われた場合は、問題なく処理できると思います。 equals()hashCode()Java のコンパレータ - 1ArrayList<>
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 = "Даша";

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

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

[Даша, Маша, Саша]
クラス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;
   }

   //...геттеры, сеттеры, 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);
   }
}
それは非常に単純です: 1 つのクラスCarと 3 つのそのオブジェクトです。リスト内の車を並べ替えてください。おそらく、「どのように並べ替えるべきですか?」と疑問に思うでしょう。名前、製造年、最高速度でしょうか?素晴らしい質問です。現時点では、クラスのオブジェクトをソートする方法がわかりませんCar。そして当然のことですが、Java もこれを知りません。Collections.sort()オブジェクトのリストをメソッドに渡そうとすると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(20012, "Lamborghini Gallardo", 290);
       Car bugatti = new Car(2010, "Bugatti Veyron", 350);

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

       //ошибка компилятора!
       Collections.sort(cars);
   }
}
そして実際のところ、言語はどのようにして、作成したオブジェクトを並べ替える方法を正確に知ることができるのでしょうか? それはプログラムの目標によって異なります。これらのオブジェクトを比較するように Java に何らかの方法で教えなければなりません。そして、必要な方法を比較してください。この目的のために、Java には特別なツールである インターフェース がありますComparable。英語では「comparable」と訳されます。オブジェクトをCar相互に比較し、何らかの方法で並べ替えるためには、クラスはこのインターフェイスを実装し、その唯一のメソッドを実装する必要があります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;
   }

   //...геттеры, сеттеры, toString()

}
注意してください:インターフェースComparable<Car>だけを指定したのではなく、インターフェースも指定しましたComparable。これは型付きインターフェイスです。つまり、関連付けられている特定のクラスを指定する必要があります。原則として、<Car>これをインターフェースから削除できますが、その場合、デフォルトでオブジェクトが比較されますObjectcompareTo(Car o)クラス内の メソッドの代わりに、次のものを用意します。
@Override
   public int compareTo(Object o) {
       return 0;
   }
もちろん、私たちにとっては、 を使用する方がはるかに簡単ですCar。メソッド内に、compareTo()マシンを比較するためのロジックを実装します。製造年ごとに並べ替える必要があるとします。おそらく、メソッドがではなくcompareTo()値を返すことに気づいたでしょう。驚かないでください。実際、2 つのオブジェクトを比較すると、次の 3 つのオプションが考えられます。 intboolean
  • а < b
  • a > b
  • a == b
値は true と false の 2 つしかないためboolean、オブジェクトを比較するのには不便です。すべてがintはるかにシンプルです。戻り値> 0が の場合、a > b。結果がcompareTo < 0の場合は、 ですа < b。結果が の場合== 0、2 つのオブジェクトは等しいことになりますa == b。製造年によって車を分類するようにクラスに教えるのは、梨の殻をむくのと同じくらい簡単です。
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
何が起きてる?this1 つの車のオブジェクト ( )、この車の製造年を取得し、そこから別の車 (オブジェクトを比較する車) の製造年を引きます。最初の車の製造年の方が大きい場合、メソッドは を返しますint > 0。つまり、車this >は車ですо。逆に、2 番目の自動車 ( о) の製造年が大きい場合、メソッドは負の数を返すため、 が返されますо > 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);

       //тут раньше была ошибка
       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 のコンパレータ - 2どのような場合に使用する必要がありますComparableか? 実装された比較方法はComparable「自然順序付け」と呼ばれます。compareTo()これは、プログラム内でこのクラスのオブジェクトに使用される最も一般的な比較メソッドをメソッドで記述するためです。Natural Ordering は Java にすでに存在します。たとえば、Java は、文字列はアルファベット順にソートされることが多く、数値は値の昇順にソートされることが多いことを認識しています。したがって、数値または文字列のリストに対してメソッドを呼び出すとsort()、それらは並べ替えられます。私たちのプログラムでほとんどの場合、自動車が製造年別に比較および並べ替えられる場合、インターフェイスComparable<Car>とメソッドを使用してそれらの自然な並べ替えを定義する価値がありますcompareTo()。しかし、それだけでは十分ではない場合はどうすればよいでしょうか? 私たちのプログラムがそれほど単純ではないことを想像してみましょう。ほとんどの場合、車の自然な分類(製造年ごとに設定)が適しています。しかし、私たちの顧客の中には高速運転のファンがいることもあります。ユーザーが選択できるように車のカタログを用意している場合は、最高速度別に注文する必要があります。 Java のコンパレータ - 3たとえば、15% のケースでそのような並べ替えが必要になります。Carこれでは、製造年ではなく速度による自然な並べ替えを設定するには明らかに十分ではありません。しかし、15% の顧客を無視することはできません。私たちは何をしますか?ここで、別のインターフェイスが役に立ちますComparator。と同じようにComparable入力されます。違いは何ですか? Comparableオブジェクトを「比較可能」にし、ほとんどの場合に使用される最も自然な並べ替え順序を作成します。 Comparator- これは別の「コンパレータ」クラスです (翻訳は少し不器用ですが、理解できます)。特定の並べ替えを実装する必要がある場合、クラスに移動してCarロジックを変更する必要はありませんcompareTo()。代わりに、プログラム内に別のコンパレータ クラスを作成し、必要な並べ替えを行うように教えることができます。
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()。これはインターフェイス メソッドでありComparator、実装する必要があります。2 つのオブジェクトを入力として受け取りCar、通常の方法 (減算) で最大速度を比較します。と同様にcompareTo()、数値を返します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()で定義された自然な並べ替えを使用しません。代わりに、渡されたコンパレータからの並べ替えアルゴリズムを適用します。これによりどのようなメリットが得られるのでしょうか? まず、書かれたコードとの互換性です。ほとんどの場合に使用される現在の並べ替え方法を維持しながら、新しい特定の並べ替え方法を作成しました。私たちはクラスにはまったく触れませんでした。彼はそのままでした。 compareTo()CarCarComparable
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();
   }

   //...геттеры, сеттеры, toString()

}
第二に、柔軟性です。必要なだけ種類を追加できます。たとえば、色、速度、重量、またはバットマンの映画でその車が使用された回数で車を分類します。追加のものを作成するだけで十分ですComparator。それだけです!今日は、仕事の実際のプロジェクトで頻繁に使用する 2 つの非常に重要なメカニズムを学びました。しかし、ご存知のとおり、実践のない理論は何の役にも立ちません。したがって、知識を統合していくつかの問題を解決しましょう。:)
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION