1. 程式人生 > >排序—物件類排序之Comparator介面

排序—物件類排序之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比較器來實現物件的排序。