Java Comparable与Comparator

Java Comparable与Comparator

Java提供了两个接口来使用类的数据成员对对象进行排序:

  1. Comparable
  2. Comparator

使用可比较接口

一个可比较的对象能够将自己与另一个对象进行比较。类本身必须实现 java.lang.Comparable 接口来比较它的实例。

考虑一个Movie类,它的成员包括,评级,名称,年份。假设我们想根据发行年份对电影列表进行排序。我们可以用Movie类实现Comparable接口,并且覆盖Comparable接口的compareTo()方法。

// A Java program to demonstrate use of Comparable
import java.io.*;
import java.util.*;
 
// A class 'Movie' that implements Comparable
class Movie implements Comparable<Movie>
{
    private double rating;
    private String name;
    private int year;
 
    // Used to sort movies by year
    public int compareTo(Movie m)
    {
        return this.year - m.year;
    }
 
    // Constructor
    public Movie(String nm, double rt, int yr)
    {
        this.name = nm;
        this.rating = rt;
        this.year = yr;
    }
 
    // Getter methods for accessing private data
    public double getRating() { return rating; }
    public String getName()   {  return name; }
    public int getYear()      {  return year;  }
}
 
// Driver class
class Main
{
    public static void main(String[] args)
    {
        ArrayList<Movie> list = new ArrayList<Movie>();
        list.add(new Movie("Force Awakens", 8.3, 2015));
        list.add(new Movie("Star Wars", 8.7, 1977));
        list.add(new Movie("Empire Strikes Back", 8.8, 1980));
        list.add(new Movie("Return of the Jedi", 8.4, 1983));
 
        Collections.sort(list);
 
        System.out.println("Movies after sorting : ");
        for (Movie movie: list)
        {
            System.out.println(movie.getName() + " " +
                               movie.getRating() + " " +
                               movie.getYear());
        }
    }
}
Java

输出:

Movies after sorting : 

Star Wars 8.7 1977

Empire Strikes Back 8.8 1980

Return of the Jedi 8.4 1983

Force Awakens 8.3 2015
Java

现在,假设我们也想按照电影的评级和名字来排序。当我们让一个集合元素具有可比性时(通过让它实现Comparable),我们只有一次机会来实现compareTo()方法。解决方案是使用比较器。

使用比较器

与Comparable不同,Comparator对于我们要比较的元素类型来说是外部的。它是一个单独的类。我们创建多个独立的类(实现了比较器),通过不同的成员进行比较。

Collections类有第二个sort()方法,它采用比较器。sort()方法调用compare()来对对象进行排序。

要通过Rating来比较电影,我们需要做3件事:

  1. 创建一个实现比较器的类(以及比较()方法,该方法完成以前由compareTo()完成的工作)。
  2. 制造一个比较器类的实例。
  3. 调用重载的sort()方法,将列表和实现比较器的类的实例都交给它。
//A Java program to demonstrate Comparator interface
import java.io.*;
import java.util.*;
 
// A class 'Movie' that implements Comparable
class Movie implements Comparable<Movie>
{
    private double rating;
    private String name;
    private int year;
 
    // Used to sort movies by year
    public int compareTo(Movie m)
    {
        return this.year - m.year;
    }
 
    // Constructor
    public Movie(String nm, double rt, int yr)
    {
        this.name = nm;
        this.rating = rt;
        this.year = yr;
    }
 
    // Getter methods for accessing private data
    public double getRating() { return rating; }
    public String getName()   {  return name; }
    public int getYear()      {  return year;  }
}
 
// Class to compare Movies by ratings
class RatingCompare implements Comparator<Movie>
{
    public int compare(Movie m1, Movie m2)
    {
        if (m1.getRating() < m2.getRating()) return -1;
        if (m1.getRating() > m2.getRating()) return 1;
        else return 0;
    }
}
 
// Class to compare Movies by name
class NameCompare implements Comparator<Movie>
{
    public int compare(Movie m1, Movie m2)
    {
        return m1.getName().compareTo(m2.getName());
    }
}
 
// Driver class
class Main
{
    public static void main(String[] args)
    {
        ArrayList<Movie> list = new ArrayList<Movie>();
        list.add(new Movie("Force Awakens", 8.3, 2015));
        list.add(new Movie("Star Wars", 8.7, 1977));
        list.add(new Movie("Empire Strikes Back", 8.8, 1980));
        list.add(new Movie("Return of the Jedi", 8.4, 1983));
 
        // Sort by rating : (1) Create an object of ratingCompare
        //                  (2) Call Collections.sort
        //                  (3) Print Sorted list
        System.out.println("Sorted by rating");
        RatingCompare ratingCompare = new RatingCompare();
        Collections.sort(list, ratingCompare);
        for (Movie movie: list)
            System.out.println(movie.getRating() + " " +
                               movie.getName() + " " +
                               movie.getYear());
 
 
        // Call overloaded sort method with RatingCompare
        // (Same three steps as above)
        System.out.println("\nSorted by name");
        NameCompare nameCompare = new NameCompare();
        Collections.sort(list, nameCompare);
        for (Movie movie: list)
            System.out.println(movie.getName() + " " +
                               movie.getRating() + " " +
                               movie.getYear());
 
        // Uses Comparable to sort by year
        System.out.println("\nSorted by year");
        Collections.sort(list);
        for (Movie movie: list)
            System.out.println(movie.getYear() + " " +
                               movie.getRating() + " " +
                               movie.getName()+" ");
    }
} 
Java

输出:

Sorted by rating
8.3 Force Awakens 2015
8.4 Return of the Jedi 1983
8.7 Star Wars 1977
8.8 Empire Strikes Back 1980

Sorted by name
Empire Strikes Back 8.8 1980
Force Awakens 8.3 2015
Return of the Jedi 8.4 1983
Star Wars 8.7 1977

Sorted by year
1977 8.7 Star Wars 
1980 8.8 Empire Strikes Back 
1983 8.4 Return of the Jedi 
2015 8.3 Force Awakens
Java
  • 可比性是指具有自然排序的对象,这意味着对象本身必须知道它是如何被排序的。例如,学生的学号。而比较器接口的排序是通过一个单独的类完成的。
  • 从逻辑上讲,可比较接口将 “这个 “引用与指定的对象进行比较,而Java中的比较器则对提供的两个不同的类对象进行比较。
  • 如果Java中的任何一个类实现了可比较接口,那么该对象的集合无论是List还是Array都可以通过使用Collections.sort()或Arrays.sort()方法自动进行排序,对象将根据CompareTo方法定义的自然顺序进行分类。
  • 一个基本的区别特征是,使用比较法我们只能使用一个比较。而我们可以根据你的需要为一个给定的类型编写多个自定义比较器,所有这些都使用对排序含义的不同解释。就像在可比较的例子中,我们可以只用一个属性进行排序,即年份,但在比较器中,我们也能够使用不同的属性,如评级、名称和年份。

总而言之,如果对象的排序需要基于自然顺序,那么就使用比较器,而如果你需要根据不同对象的属性进行排序,那么就使用Java中的比较器。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

登录

注册