排序—物件類排序之Comparator介面
WHY:當需要對某個類進行排序,但是這個類本身並不支援排序時,可以用到比較器,java中定義了兩種比較器的型別,第一種是comparator可用於陣列或者集合的排序,第二種是comparable可用於陣列的排序。
首先來講一下comparator比較器
場景1
需要對單位的員工資訊列表進行排序,要求如下:
1、級別高的排在前面
2、同級別的,工資高的排在前面
3、同工資的,資歷老的排在前面
STEP ONE:建立Employee類
public class Employee implements Serializable { private static final long serialVersionUID = 4775629632953317597L; public int id; public int level; public int salary; public int year; public int getId() { return id; } public void setId(int id) { this.id = id; } public int getLevel() { return level; } public void setLevel(int level) { this.level = level; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public Employee(int id, int level, int salary, int year) { this.id = id; this.level = level; this.salary = salary; this.year = year; } }
STEP TWO:建立Comparator比較器
public class EmpComparator implements Comparator<Employee> { @Override public int compare(Employee employee1, Employee employee2) { int cr = 0; //按級別降序排列 int a = employee2.getLevel() - employee1.getLevel(); if (a != 0) { cr = (a > 0) ? 3 : -1; } else { //按薪水降序排列 a = employee2.getSalary() - employee1.getSalary(); if (a != 0) { cr = (a > 0) ? 2 : -2; } else { //按入職年數降序排列 a = employee2.getYear() - employee1.getYear(); if (a != 0) { cr = (a > 0) ? 1 : -3; } } } return cr; } }
STEP THREE:建立單元測試主類,測試排序結果
public class SortTest { public static void main(String[] args) { List<Employee> employeeList = new ArrayList<Employee>() { { add(new Employee(1, 9, 10000, 10)); add(new Employee(2, 9, 12000, 7)); add(new Employee(3, 5, 10000, 12)); add(new Employee(4, 5, 10000, 6)); add(new Employee(5, 3, 5000, 3)); add(new Employee(6, 1, 2500, 1)); add(new Employee(7, 5, 8000, 10)); add(new Employee(8, 3, 8000, 2)); add(new Employee(9, 1, 3000, 5)); add(new Employee(10, 1, 2500, 4)); add(new Employee(11, 2, 2000, 4)); } }; Collections.sort(employeeList, new EmpComparator()); System.out.println("ID\tLevel\tSalary\tYears"); System.out.println("============================="); for (Employee employee : employeeList) { System.out.printf("%d\t%d\t%d\t%d\n", employee.getId(), employee.getLevel(), employee.getSalary(), employee.getYear()); } System.out.println("============================="); } }
以上程式碼就完整的演示了使用比較器介面Comparator,對本身不支援排序的實體類進行排序的整個過程,接著我們來介紹一下java.util.Comparator介面的工作原理:
Comparator介面的原始碼是:
public interface Comparator{
int compare(T o1,T o2);
boolean equals(Object obj) ;
}
當一個類要實現Comparator介面時,它必須要實現compare函式,而equals函式則可以不實現
本身的話,int compare(T o1,To2)函式是比較o1,o2的大小,
如果返回負值則意味著o1比o2小;否則o1等於o2;返回正值則意味著o1比o2大
但是在Comparator的實現類中要重寫compare方法
在Comparator比較器中升降序可以理解為:
如果o1比o2大,若返回重寫後的compare方法返回的是正數,此時呼叫的函式Collection.sort()就是升序,若返回的是負數,此時呼叫的函式Collection.sort()就是降序
同理如果o1比o2小,若返回的是負數,此時呼叫的函式Collection.sort()就是升序,若返回的是正數,此時呼叫的函式Collection.sort()就是降序
總結一句就是說,重寫後的compare方法,返回的值若與compare(T o1,T o2)函式同正負號則是升序排列,若正負號相反則降序排列
public class EmpComparator implments Comparator<Employee>{
public int compare(Employee e1,Employee e2){
if(e1.getLevel()>e2.getLevel())
{return -1;}
}
}
像如上所示的程式碼,e1的級別大於e2的級別,但是在Comparator介面的實現類EmpComparator的重寫的compare方法中卻返回的是負數,因此EmpComparator實現的是僱員按照級別降序排列
場景2
java的比較器有兩類,一種是comparator在場景一中已經詳細描述了,另一種是comparable介面,我們現在來講第二種。
先說一下為什麼有兩種比較器呢,我們先來看一下comparable介面是如何工作的:
讓需要排序的類實現comparable介面,在其中重寫compareTo(T o)方法,並在其中定義排序規則,就可以直接用java.util.Arrays.util來排列物件
用comparable的好處在於,直接在物件中就定義了排序的規則,不用再重新重新寫比較器的實現類
class Student implements Comparable<Student>{
private String name;
private int age;
private float score;
public Student(String name, int age, float score) {
this.name = name;
this.age = age;
this.score = score;
}
public String toString()
{
return name+"\t\t"+age+"\t\t"+score;
}
@Override
public int compareTo(Student o) {
// TODO Auto-generated method stub
if(this.score>o.score)//score是private的,為什麼能夠直接呼叫,這是因為在Student類內部
return -1;//由高到底排序
else if(this.score<o.score)
return 1;
else{
if(this.age>o.age)
return 1;//由底到高排序
else if(this.age<o.age)
return -1;
else
return 0;
}
}
}
public class ComparableDemo01 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Student stu[]={new Student("zhangsan",20,90.0f),
new Student("lisi",22,90.0f),
new Student("wangwu",20,99.0f),
new Student("sunliu",22,100.0f)};
java.util.Arrays.sort(stu);
for(Student s:stu)
{
System.out.println(s);
}
}
}
看完了comparable比較器之後我們來說一下為什麼有兩種比較器:
因為有些類在設計的時候沒有考慮讓其實現comparable介面,因此才有了comparator比較器用以補救。
場景3
我們看到,需要排列的物件,有時候是裝在數組裡,有時候是裝在集合裡,相應的也就需要呼叫不同的排序方法,
當物件裝在陣列中時
如果是用的comparator比較器,則呼叫Arrays.sort()方法,需要傳遞兩個引數,(陣列名 new EmpComparator())
如果用的是comparable比較器,則呼叫Arrays.sort()方法,需要傳遞一個引數,(陣列名)
當物件裝在集合中時
則只能呼叫Collection.sort()方法,需要傳遞兩個引數(集合名 new EmpComparator()),即物件和比較器,這也就意味著集合只能用comparator比較器來實現物件的排序。