JavaRush /Blog Java /Random-MS /Pembanding di Jawa

Pembanding di Jawa

Diterbitkan dalam kumpulan
hello! Hari ini kita akan bercakap tentang membandingkan objek. Hmm... Tetapi kita nampaknya sudah bercakap tentang ini lebih daripada sekali? :/ Kami tahu cara ==pengendali “ ” berfungsi, serta kaedah equals()dan hashCode(). Perbandingan sebenarnya bukan tentang itu. Sebelum ini, kami bermaksud lebih seperti "objek ujian untuk kesaksamaan." Pembanding dalam Java - 1Tetapi membandingkan objek antara satu sama lain mungkin mempunyai matlamat yang sama sekali berbeza! Yang paling jelas ialah menyusun. Saya fikir jika anda diberitahu untuk mengisih senarai ArrayList<>nombor atau rentetan, anda boleh mengendalikannya tanpa masalah:
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);
   }
}
Output konsol:

[Даша, Маша, Саша]
Sangat bagus jika anda mengingati kelas Collectionsdan kaedahnya sort(). Saya tidak fikir akan ada sebarang masalah dengan nombor sama ada. Berikut ialah tugas yang lebih sukar untuk anda:
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);
   }
}
Ia sangat mudah: kelas Cardan 3 objeknya. Jadilah baik untuk mengisih kereta dalam senarai! Anda mungkin akan bertanya: "Bagaimanakah ia harus diisih?" Dengan nama, mengikut tahun pembuatan, dengan kelajuan maksimum? Soalan yang hebat. Kami tidak tahu pada masa ini bagaimana untuk mengisih objek kelas Car. Dan, secara semula jadi, Java juga tidak tahu ini! Apabila kami cuba menghantar Collections.sort()senarai objek ke kaedah Car, kami akan menerima ralat:
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);
   }
}
Dan sebenarnya, bagaimana bahasa mengetahui dengan tepat cara mengisih objek yang anda tulis? Ia bergantung kepada matlamat program anda. Kita perlu mengajar Java untuk membandingkan objek ini. Dan bandingkan cara yang kita perlukan. Untuk tujuan ini, Java mempunyai alat khas - antara muka Comparable. Dalam bahasa Inggeris ini diterjemahkan sebagai "setanding". Agar objek kita Cardibandingkan antara satu sama lain dan entah bagaimana disusun, kelas mesti melaksanakan antara muka ini dan melaksanakan satu-satunya kaedahnya: 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()

}
Beri perhatian:kami menentukan antara muka Comparable<Car>, bukan sahaja Comparable. Ini ialah antara muka yang ditaip, iaitu, ia memerlukan penentuan kelas tertentu yang dikaitkan dengannya. Pada dasarnya, <Car>anda boleh mengalih keluarnya daripada antara muka, tetapi kemudian ia membandingkan objek secara lalai Object. Daripada kaedah compareTo(Car o)dalam kelas kami, kami akan mempunyai:
@Override
   public int compareTo(Object o) {
       return 0;
   }
Sudah tentu, lebih mudah untuk kita bekerja dengan Car. Di dalam kaedah compareTo()kami melaksanakan logik untuk membandingkan mesin. Katakan kita perlu menyusunnya mengikut tahun pembuatan. Anda mungkin perasan bahawa kaedah itu compareTo()mengembalikan nilai int, bukan boolean. Jangan biarkan ini mengejutkan anda. Faktanya ialah membandingkan dua objek memberi kita 3 pilihan yang mungkin:
  • а < b
  • a > b
  • a == b.
Ia booleanhanya mempunyai 2 nilai - benar dan salah, yang menyusahkan untuk membandingkan objek. Semuanya intlebih mudah. Jika nilai pulangan > 0ialah , maka a > b. Jika hasilnya compareTo < 0, maka а < b. Nah, jika hasilnya ialah == 0, maka kedua-dua objek adalah sama: a == b. Mengajar kelas kami untuk mengisih kereta mengikut tahun pembuatan adalah semudah membedil pear:
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
Apa yang berlaku di sini? Kami mengambil satu objek kereta ( this), tahun pembuatan kereta ini, dan tolak daripadanya tahun pembuatan kereta lain (yang dengannya kami membandingkan objek itu). Jika tahun pembuatan kereta pertama lebih besar, kaedah itu akan kembali int > 0. Maksudnya kereta this >ialah kereta о. Jika, sebaliknya, tahun pembuatan kereta kedua ( о) lebih besar, maka kaedah itu akan mengembalikan nombor negatif, dan oleh itu о > this. Nah, jika mereka sama, kaedah itu akan kembali 0. Mekanisme mudah sedemikian sudah cukup untuk mengisih koleksi objek Car! Anda tidak perlu melakukan apa-apa lagi. Di sini anda:
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);
   }
}
Output konsol:

[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}]
Kereta-kereta itu disusun sebagaimana mestinya! :) Pembanding dalam Java - 2Dalam kes apakah ia harus digunakan Comparable? Kaedah perbandingan yang dilaksanakan Comparabledipanggil "pesanan semula jadi". Ini kerana dalam kaedah compareTo()anda menerangkan kaedah perbandingan yang paling biasa yang akan digunakan untuk objek kelas ini dalam program anda. Susunan Asli sudah ada di Jawa. Sebagai contoh, Java mengetahui bahawa rentetan paling kerap diisih mengikut abjad, dan nombor paling kerap diisih mengikut nilai menaik. Oleh itu, jika anda memanggil kaedah pada senarai nombor atau rentetan sort(), ia akan diisih. Jika dalam program kami kereta dalam kebanyakan kes akan dibandingkan dan diisih mengikut tahun pembuatan, maka ia patut menentukan jenis semula jadi untuk mereka menggunakan antara muka Comparable<Car>dan kaedah compareTo(). Tetapi bagaimana jika itu tidak mencukupi untuk kita? Bayangkan program kami tidak begitu mudah. Dalam kebanyakan kes, pengisihan semula jadi kereta (kami menetapkannya mengikut tahun pembuatan) sesuai dengan kami. Tetapi kadang-kadang di kalangan pelanggan kami ada peminat pemanduan pantas. Jika kami menyediakan katalog kereta untuk mereka pilih, mereka perlu dipesan mengikut kelajuan maksimum. Pembanding dalam Java - 3Sebagai contoh, kita memerlukan pengisihan sedemikian dalam 15% kes. Ini jelas tidak mencukupi untuk menetapkan pengisihan semula jadi Carmengikut kelajuan dan bukannya tahun pembuatan. Tetapi kita tidak boleh mengabaikan 15% pelanggan. Apa yang kita lakukan? Di sini antara muka lain datang untuk membantu kami - Comparator. Sama seperti , Comparableia ditaip. Apa perbezaannya? Comparablemenjadikan objek kita "setanding" dan mencipta susunan isihan paling semula jadi untuknya yang akan digunakan dalam kebanyakan kes. Comparator- ini adalah kelas "pembanding" yang berasingan (terjemahannya agak kekok, tetapi boleh difahami). Jika kita perlu melaksanakan beberapa pengisihan tertentu, kita tidak perlu masuk ke dalam kelas Cardan menukar logik compareTo(). Sebaliknya, kami boleh mencipta kelas pembanding yang berasingan dalam program kami dan mengajarnya untuk melakukan pengisihan yang kami perlukan!
import java.util.Comparator;

public class MaxSpeedCarComparator implements Comparator<Car> {

   @Override
   public int compare(Car o1, Car o2) {
       return o1.getMaxSpeed() - o2.getMaxSpeed();
   }
}
Seperti yang anda lihat, cara kami Comparatoragak mudah. Terdapat hanya satu kaedah compare()- ini ialah kaedah antara muka Comparator, yang mesti dilaksanakan. Ia mengambil dua objek sebagai input Cardan membandingkan kelajuan maksimumnya dengan cara biasa (mengikut penolakan). Seperti compareTo(), ia mengembalikan nombor int, prinsip perbandingan adalah sama. Bagaimana kita boleh menggunakan ini? Sangat ringkas:
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);
   }
}
Output konsol:

[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}]
Kami hanya mencipta objek pembanding dan menyampaikannya kepada kaedah Collections.sort()bersama-sama dengan senarai untuk diisih. Setelah menerima pembanding sebagai input, kaedah sort()tidak akan menggunakan pengisihan semula jadi yang ditakrifkan dalam kaedah compareTo()kelas Car. Sebaliknya, ia akan menggunakan algoritma pengisihan daripada pembanding yang dihantar kepadanya. Apakah kelebihan yang diberikan ini kepada kita? Pertama, keserasian dengan kod bertulis. Kami mencipta kaedah pengisihan khusus yang baharu, sambil mengekalkan kaedah semasa, yang akan digunakan dalam kebanyakan kes. Kami tidak menyentuh kelas langsung Car. Dia Comparablekekal seperti sedia ada:
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()

}
Kedua, fleksibiliti. Kita boleh menambah seberapa banyak jenis yang kita mahu. Katakan, susun kereta mengikut warna, kelajuan, berat atau berapa kali kereta itu digunakan dalam filem Batman. Ia cukup hanya untuk mencipta satu tambahan Comparator. Itu sahaja! Hari ini anda mempelajari dua mekanisme yang sangat penting yang sering anda gunakan dalam projek sebenar di tempat kerja. Tetapi, seperti yang anda tahu, teori tanpa amalan bukanlah apa-apa. Oleh itu, sudah tiba masanya untuk menyatukan pengetahuan anda dan menyelesaikan beberapa masalah! :)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION