CodeGym /Java 博客 /随机的 /Java的比较器类
John Squirrels
第 41 级
San Francisco

Java的比较器类

已在 随机的 群组中发布
你好!今天我们要谈谈比较对象。 Java 的比较器类 - 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);
   }
}
任务其实很简单。我们有一个Car类和 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对象,类必须实现这个接口,它由一个方法组成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()方法返回一个int,而不是一个boolean。不要让这让你感到惊讶。当我们比较两个对象时,有 3 种可能性:
  • а < b
  • a > b
  • a == b.
boolean只有 2 个值:true 和 false,这不适用于比较对象。有了int,一切都简单多了。如果返回值为> 0,则a > b。如果的结果compareTo< 0,那么a < b。并且,如果结果为== 0,则两个对象相等:a == b。教我们的班级按制造年份对汽车进行分类很容易:

@Override
public int compareTo(Car o) {
   return this.getManufactureYear() - o.getManufactureYear();
}
但是这里发生了什么?我们获取一个 Car 对象 ( this),获取这辆车的制造年份,并从中减去另一辆汽车(与该对象进行比较的汽车)的制造年份。如果第一辆汽车的制造年份更大,该方法将返回一个int > 0. 这意味着this car >汽车o。相反,如果第二辆车的制造年份 ( о) 更大,则该方法将返回一个负数,这意味着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 的比较器类 - 2我应该什么时候使用Comparable?中实现的比较方法Comparable称为自然排序。这是因为在compareTo()方法中,您定义了比较此类对象的最常见或最自然的方式。Java 已经有了自然顺序。例如,Java 知道字符串通常按字母顺序排序,而数字则按数值递增排序。因此,如果您sort()在数字或字符串列表上调用该方法,它们将被排序。如果我们的程序通常按制造年份对汽车进行比较和排序,那么我们应该使用接口Comparable<Car>compareTo()方法。但是,如果这对我们来说还不够怎么办?假设我们的程序不是那么简单。在大多数情况下,汽车的自然分类(我们已将其设置为按制造年份执行)适合我们。但有时我们的客户是快速驾驶的狂热爱好者。如果我们正在准备一份汽车目录供他们阅读,那么汽车应该按最高速度排序。 Java 的比较器类 - 3例如,假设我们有 15% 的时间需要这样排序。这显然不足以让我们将Car班级的自然排序设置为按速度而不是按制造年份。但是我们不能忽视15%的客户。那么我们该怎么办?另一个接口在这里为我们提供帮助:Comparator。就像Comparable,它是一个参数化的接口。有什么不同? Comparable使我们的对象“可比较”并定义它们最自然的排序顺序,即在大多数情况下将使用的排序顺序。 Comparator是一个单独的“比较”界面。如果我们需要实现某种特殊的排序顺序,我们不需要深入到类中去Car改变.class的逻辑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非常简单。我们只需要实现一个接口方法:compare(). 它以两个Car对象作为输入,并以通常的方式(通过减法)比较它们的最大速度。like 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()方法接收比较器时,它不使用CarcompareTo()方法中定义的自然排序。相反,它应用由传递给它的比较器定义的排序算法。 这样做有什么好处?首先,与现有代码的兼容性。我们创建了一种新的特殊排序方法,同时保留了大部分时间都会使用的现有方法。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()

}
第二,灵活性。我们可以添加任意多的排序算法。例如,我们可以按颜色、速度、重量或汽车在蝙蝠侠电影中的使用次数对汽车进行分类。我们需要做的就是创建一个额外的Comparator. 就是这样!今天你学习了两个非常重要的机制,你在工作中会经常在实际项目中使用它们。但是,如您所知,没有实践的理论是无用的。现在是时候巩固您的知识并完成一些任务了!
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION