Java中Comparable 和 Comparator
Java中的Comparable和Comparator是用于对对象集合进行排序的两个接口。显而易见的问题是,为什么两个接口都执行相同的对象排序任务。在这篇文章中,我们将看到Java中什么是Comparable和Comparator接口,为什么都需要它们以及Java中Comparable和Comparator之间的区别。
Java中的接口Comparable
Java中的可比接口只有一个方法compareTo()。
int compareTo(T o)–此方法将用于调用该方法的对象与作为参数传递的对象进行比较。
根据compareTo()方法的实现,实现此接口的类的对象进行排序。由于类本身是在实现接口,因此Comparable接口提供的排序称为类的自然排序。
可以通过Collections.sort(和Arrays.sort)对存储实现该接口的类的对象的列表(和数组)进行自动排序。实现此接口的对象可以用作排序映射中的键(即TreeMap)或者用作排序集中的元素(即TreeSet),而无需指定Comparator。
Java中的接口Comparator
Java中的比较器接口具有方法compare()。
int compare(T o1,T o2)–比较其两个参数的顺序。当第一个参数小于,等于或者大于第二个参数时,返回负整数,零或者正整数。
比较器接口不是使用比较器接口实现提供的顺序排序的类的一部分。比较器接口被实现为单独的类或者匿名类。
可以将比较器传递给排序方法(例如Collections.sort或者Arrays.sort),以实现对排序顺序的精确控制。
Java Comparable 和 Comparator示例
让我们看一个例子,看看如何使用Comparable和Comparator进行排序,以及为什么都需要它们。
有一个Person类,其字段为firstName,lastName和age。我们想使用firstName + lastName对Person类对象进行排序,以便该类实现Comparable接口,并通过覆盖compareTo()方法为该顺序提供逻辑。
public class Person implements Comparable { private String firstName; private String lastName; private int age; Person(String firstName, String lastName, int age){ this.firstName = firstName; this.lastName = lastName; this.age = age; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override // For sort order - sort on first name, // if equal then sort on lastname public int compareTo(Person o) { int comp = this.getFirstName().compareTo(o.getFirstName()); return comp != 0 ? comp : this.getLastName().compareTo(o.getLastName()); } @Override public String toString() { return getFirstName() + " " + getLastName() + " " + getAge(); } }
下一个类用于创建Person类对象,并通过调用Collections.sort()方法进行排序。由于存储在List中的对象已经在实现Comparable接口,因此将使用该实现对对象进行排序。
public class SortDemo { public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("William", "Shatner", 60)); personList.add(new Person("William", "Brooks", 25)); personList.add(new Person("Persis", "Khambatta", 50)); personList.add(new Person("James", "Doohan", 70)); personList.add(new Person("DeForest", "Kelley", 65)); System.out.println("-- Original List --"); for(Person person : personList){ System.out.println("" + person); } // Sort the list Collections.sort(personList); System.out.println("--Sorted List--"); for(Person person : personList){ System.out.println("" + person); } } }
输出:
-- Original List - William Shatner 60 William Brooks 25 Persis Khambatta 50 James Doohan 70 DeForest Kelley 65 --Sorted List- DeForest Kelley 65 James Doohan 70 Persis Khambatta 50 William Brooks 25 William Shatner 60
到目前为止,我们已经有了自己的班级,班级的自然排序也可以通过实现Comparable接口来定义。
现在,假设我们有一个新要求,即按年龄或者姓氏和名字对Person类进行排序。 Person类已经与Comparable接口以及该接口施加的顺序耦合在一起。在这种情况下,我们可以使用Comparator接口,因为Comparator可以由另一个类实现,因此我们可以为不同的排序顺序创建不同的Comparator类。然后,我们可以使用Collections.sort()方法,其中还将传递Comparator来对对象进行排序。
public class Person implements Comparable<Person> { private String firstName; private String lastName; private int age; Person(String firstName, String lastName, int age){ this.firstName = firstName; this.lastName = lastName; this.age = age; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override // For sort order - sort on first name, // if equal then sort on lastname public int compareTo(Person o) { int comp = this.getFirstName().compareTo(o.getFirstName()); return comp != 0 ? comp : this.getLastName().compareTo(o.getLastName()); } @Override public String toString() { return getFirstName() + " " + getLastName() + " " + getAge(); } } // Sorting using age field class AgeComparator implements Comparator<Person>{ @Override public int compare(Person o1, Person o2) { return o1.getAge() >= (o2.getAge()) ? 1 : -1; } } //Sorting using last name if equal then sort on firstName class NameComparator implements Comparator<Person>{ @Override public int compare(Person o1, Person o2) { int comp = o1.getLastName().compareTo(o2.getLastName()); if(comp == 0){ comp = o1.getFirstName().compareTo(o2.getFirstName()); } return comp; } }
如我们所见,添加了两个新的Comparator类,一个按年龄排序,另一个按姓氏排序。 Person类仍然具有其Comparable接口实现,以定义其自然顺序。
public class SortDemo { public static void main(String[] args) { List<Person> personList = new ArrayList<Person>(); personList.add(new Person("William", "Shatner", 60)); personList.add(new Person("William", "Brooks", 25)); personList.add(new Person("Persis", "Khambatta", 50)); personList.add(new Person("James", "Doohan", 70)); personList.add(new Person("DeForest", "Kelley", 65)); System.out.println("-- Original List --"); for(Person person : personList){ System.out.println("" + person); } // Sort the list by age Collections.sort(personList, new AgeComparator()); System.out.println("--Sorted List by Age--"); for(Person person : personList){ System.out.println("" + person); } // Sort the list by last name Collections.sort(personList, new NameComparator()); System.out.println("--Sorted List by Last Name--"); for(Person person : personList){ System.out.println("" + person); } // Sort the list by first name - Natural ordering Collections.sort(personList); System.out.println("--Sorted List by first name--"); for(Person person : personList){ System.out.println("" + person); } } }
输出:
-- Original List - William Shatner 60 William Brooks 25 Persis Khambatta 50 James Doohan 70 DeForest Kelley 65 --Sorted List by Age- William Brooks 25 Persis Khambatta 50 William Shatner 60 DeForest Kelley 65 James Doohan 70 --Sorted List by Last Name- William Brooks 25 James Doohan 70 DeForest Kelley 65 Persis Khambatta 50 William Shatner 60 --Sorted List by first name- DeForest Kelley 65 James Doohan 70 Persis Khambatta 50 William Brooks 25 William Shatner 60
如我们现在所看到的,如果要按年龄排序,则可以在Collections.sort()方法中传递按年龄排序的比较器。如果要按lastName字段进行排序,则采用相同的方法,则可以在Collections.sort()方法中传递按lastName排序的Comparator。如果要按firstName排序,则仍然具有Comparable接口的实现所提供的实现。
Java中Comparable和Comparator之间的区别
Comparable | Comparator |
---|---|
比较接口具有用于提供排序逻辑的compareTo()</ strong>方法。 | 比较器接口具有用于提供排序逻辑的compare()</ strong>方法。 |
比较接口在java.lang包中。 | 比较器接口在java.util包中。 |
比较接口由要对其对象进行排序的类实现。 | 比较器接口由某些其他类或者作为匿名类实现。 |
由于要对对象进行排序的类实现了Comparable接口,因此Comparable只能提供一种对对象进行排序的方法。 | 可以有许多Comparator类为不同的排序顺序提供逻辑。 |
具有实现Comparable接口的对象的列表或者数组可以通过仅将Collections.sort()中的List传递或者通过对数组使用Arrays.sort()来进行排序。 | 对于Comparator,必须传递Comparator的实例使用Collections.sort()方法。 |