JavaRush /Java 博客 /Random-ZH /Java 中的比较器

Java 中的比较器

已在 Random-ZH 群组中发布
你好!今天我们将讨论比较对象。嗯……不过这个问题我们好像已经讨论过不止一次了?:/ 我们知道“ ==”运算符如何工作,以及equals()and方法hashCode()。比较并不是真的。以前,我们的意思更像是“测试对象的平等性”。Java 中的比较器 - 1但相互比较对象可能有完全不同的目标!最明显的就是排序。我认为如果你被告知对数字或字符串列表进行排序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 = "Даша";

       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);
   }
}
它非常简单:一个类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。在英语中,这被翻译为“可比较的”。为了使我们的对象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>您可以将其从界面中删除,但它会默认比较对象Object。我们将使用以下方法来代替compareTo(Car o)类中的方法:
@Override
   public int compareTo(Object o) {
       return 0;
   }
当然,我们合作起来要容易得多Car。在该方法内部,compareTo()我们实现了比较机器的逻辑。假设我们需要按制造年份对它们进行排序。您可能注意到该方法compareTo()返回值int,而不是boolean。不要让这让你感到惊讶。事实上,比较两个对象给了我们 3 种可能的选择:
  • а < b
  • a > b
  • a == b
boolean只有2个值——true和false,这对于比较对象来说很不方便。一切都int简单得多。如果返回值为> 0,则a > b. 如果结果compareTo < 0是的话а < b。好吧,如果结果是== 0,那么这两个对象是相等的:a == b。教我们的班级按制造年份对汽车进行分类就像剥梨子一样简单:
@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
这里发生了什么?我们获取一个汽车对象 ( this),即该汽车的制造年份,并从中减去另一辆车(我们与该对象进行比较的汽车)的制造年份。如果第一辆汽车的制造年份更大,该方法将返回int > 0。这意味着汽车this >就是汽车о。相反,如果第二辆汽车的制造年份 ( о) 更大,则该方法将返回负数,因此о > 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(),您描述了将用于程序中此类的对象的最常见比较方法。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非常简单。只有一个方法compare()——这是一个接口方法Comparator,必须实现它。它以两个物体作为输入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。就这样!今天您学习了两个非常重要的机制,您将在实际工作项目中经常使用它们。但是,如您所知,没有实践的理论毫无意义。因此,是时候巩固你的知识并解决几个问题了!:)
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION