目錄
- 1. 自然排序:java.lang.Comparable
- 2. 定制排序:java.util.Compartor
- 3. 比較方法的回傳值正負與升序、降序的關系
- 4. Comparable介面和Comparator介面的區別
在Java中經常會涉及到多個物件的排序問題,那么就涉及到物件之間的比較,
Java實作物件排序的方式有兩種:
自然排序:java.lang.Comparable
定制排序:ava.util.Comparator
1. 自然排序:java.lang.Comparable
-
Comparable介面強行對實作它的每個類的物件進行整體排序,這種排序被稱為類的自然排序,Comparable介面中只有一個抽象方法:int compareTo(Object o);, -
實作
Comparable的類必須實作compareTo(Object o)方法,兩個物件即通過compareTo(Object o)方法的回傳值來比較大小,- 如果當前物件 this 大于形參物件 o ,則回傳正整數,
- 如果當前物件 this 小于形參物件 o ,則回傳負整數,
- 如果當前物件 this 等于形參物件 o ,則回傳零,
-
實作
Comparable介面的類的物件陣列(和有序集合)可以通過 Arrays.sort(和 Collections.sort )進行自動排序, -
Comparable的典型實作:(默認都是從小到大排序)
String、包裝類等實作了Comparable介面,重寫了compareTo(obj)方法
String:按照字串中字符的Unicode值進行比較
數值型別對應的包裝類以及BigInteger、BigDecimal:按照它們對應的數值大小進行比較
Character:按照字符的Unicode值來進行比較
Boolean:true 對應的包裝類實體大于 false 對應的包裝類實體
Date、Time等:后面的日期時間比前面的日期時間大代碼示例:
String[] arr = new String[]{"AA","cc","ac","dd","aa","FF","ff"}; Arrays.sort(arr); System.out.println(Arrays.toString(arr)); // [AA, FF, aa, ac, cc, dd, ff] -
對于自定義類來說,如果需要排序,我們可以讓自定義類實作
Comparable介面,重寫compareTo(Object o)方法,在compareTo(Object o)方法中指明如何排序,定義學生類:
public class Student { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }測驗類:
public class ComparableTest { public static void main(String[] args) { Student[] students = new Student[5]; students[0] = new Student("rose", 16); students[1] = new Student("jack", 18); students[2] = new Student("mark", 16); students[3] = new Student("john", 16); students[4] = new Student("lily", 17); Arrays.sort(students); for (int i = 0; i < students.length; i++) { System.out.println(students[i]); } } }發現程式出現了型別轉換例外:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ggMQjfNv-1598369086597)(img/Comparable.png)]
原因:對于自定義類來說,如果需要排序,自定義類必須實作
Comparable介面,重寫compareTo(Object o)方法,在compareTo(Object o)方法中指明如何排序,修改Student類,實作
Comparable介面,指定按學生年齡升序排序:public class Student implements Comparable { ... @Override public int compareTo(Object o) { Student student = (Student) o; if (this.age < student.age) { return -1; } if (this.age > student.age) { return 1; } return 0; } }運行結果:
Student{name='mark', age=15}
Student{name='rose', age=16}
Student{name='john', age=16}
Student{name='lily', age=17}
Student{name='jack', age=18}如果要按學生年齡降序排序,則修改compareTo方法:當前物件的年齡小于引數物件時,回傳正整數;當前物件大于引數物件時,回傳負整數:
@Override public int compareTo(Object o) { Student student = (Student) o; if (this.age < student.age) { return 1; } if (this.age > student.age) { return -1; } return 0; }
2. 定制排序:java.util.Compartor
-
當元素的型別沒有實作
java.lang.Comparable介面而又不方便修改代碼,或者實作了java.lang.Comparable介面的排序規則不適合當前的操作,那么可以考慮使用Comparator介面的實作類來排序, -
Comparator介面中只有兩個抽象方法int compare(Object o1, Object o2);、boolean equals(Object obj);,Comparator介面實作類默認繼承了Object類的equals方法,即間接實作了equals方法,因此只需實作int compare(Object o1, Object o2)即可, -
可以將
Comparator介面實作類傳遞給 sort 方法(如 Arrays.sort 或 Collections.sort),從而允許在排序順序上實作精確控制, -
重寫
int compare(Object o1, Object o2)方法,比較o1和o2的大小:如果要按照升序排序,
則 o1小于o2回傳負整數,o1與o2相等回傳0,01大于02回傳正整數如果要按照降序排序
則 o1小于o2回傳正整數,o1與o2相等回傳0,01大于02回傳負整數代碼演示:
定義Student類,無需實作Comparable介面:
public class Student { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }測驗類:向sort方法中傳入待排序的陣列物件和Comparator介面實作類,指定按學生年齡升序排序:
public class ComparableTest { public static void main(String[] args) { Student[] students = new Student[5]; students[0] = new Student("rose", 16); students[1] = new Student("jack", 18); students[2] = new Student("mark", 15); students[3] = new Student("john", 16); students[4] = new Student("lily", 17); Arrays.sort(students, new Comparator() { @Override public int compare(Object o1, Object o2) { Student s1 = (Student) o1; Student s2 = (Student) o2; //下面的代碼可簡化為 return s1.getAge() - s2.getAge(); if (s1.getAge() < s2.getAge()) { return -1; } if (s1.getAge() > s2.getAge()) { return 1; } return 0; } }); for (int i = 0; i < students.length; i++) { System.out.println(students[i]); } } }運行結果:
Student{name='mark', age=15}
Student{name='rose', age=16}
Student{name='john', age=16}
Student{name='lily', age=17}
Student{name='jack', age=18}如果要按學生年齡降序排序,則修改compare方法:當前物件的年齡小于引數物件時,回傳正整數;當前物件大于引數物件時,回傳負整數:
@Override public int compare(Object o1, Object o2) { Student s1 = (Student) o1; Student s2 = (Student) o2; //下面的代碼可簡化為 return s2.getAge() - s1.getAge(); if (s1.getAge() < s2.getAge()) { return 1; } if (s1.getAge() > s2.getAge()) { return -1; } return 0; }按年齡降序排序,年齡相同時按姓名首字母升序排序:
@Override public int compare(Object o1, Object o2) { Student s1 = (Student) o1; Student s2 = (Student) o2; //第一條排序規則:年齡降序 int result = s2.getAge() - s1.getAge(); //第二條排序規則:年齡相同時,姓名首字母升序 if (result == 0) { result = s1.getName().charAt(0) - s2.getName().charAt(0); } return result; }運行結果:
Student{name='jack', age=18}
Student{name='lily', age=17}
Student{name='john', age=16}
Student{name='rose', age=16}
Student{name='mark', age=15}
3. 比較方法的回傳值正負與升序、降序的關系
從前面已經知道:如果要按照升序排序,則 o1小于o2回傳負整數,o1與o2相等回傳0,01大于02回傳正整數
如果要按照降序排序,則 o1小于o2回傳正整數,o1與o2相等回傳0,01大于02回傳負整數
那么,對元素升序、降序排序時調整元素位置與介面中回傳值的正負有什么關系呢?
測驗環境:JDK8
原陣列元素順序:
Student{name='rose', age=16}
Student{name='jack', age=18}
Student{name='mark', age=15}
Student{name='john', age=16}
Student{name='lily', age=17}
- 在compare方法中,不管o1、o2物件的內容,統一回傳正整數:
@Override
public int compare(Object o1, Object o2) {
return 1;
}
運行結果發現,陣列元素順序未改變,
- 在compare方法中,不管o1、o2物件的內容,統一放回負整數,運行結果發現,陣列元素倒置,
- 在compare方法中,不管o1、o2物件的內容,統一放回0,運行結果發現,陣列元素順序未改變,
在comparable介面中及集合中的運行結果一致,
從而得出結論:在呼叫 compare(Object o1, Object o2) 方法時,會把兩個元素中索引較小的元素賦值給o2,索引較大的元素賦值給o1,Comparable介面中compareTo(Object o) 方法的呼叫者是兩個元素中索引較大的元素,引數物件 o 則是索引較小的元素,(JDK版本不同,對應關系可能不同),通過debug除錯或查看原始碼也能得出這個結論,
比如,對于陣列{5, 10, 20, 15},比較前兩個元素呼叫 compare(Object o1, Object o2) 方法時,會把5賦值給o2,把10賦值給o1,按升序排序時,若o1 > o2,則回傳正整數,不調整元素位置;若o1 == o2,則回傳0,不調整元素位置;若o1 < o2,則回傳負整數,調整元素位置,按降序排序時,若o1 > o2,則回傳負整數,需要調整元素位置;若o1 == o2,則回傳0,不調整元素位置;若o1 < o2,則回傳正整數,不調整元素位置,因此,不管是升序還是降序,只有在回傳負整數時,才會調整元素的位置,
綜上,排序時是否需要調整元素位置是由物件o1、o2與陣列中元素的對應關系 和 比較方法回傳值的正負共同決定的,
4. Comparable介面和Comparator介面的區別
只要實作Comparable 介面的物件直接就成為一個可以比較的物件,但是需要修改源代碼,
用Comparator 的好處是不需要修改源代碼, 而是在待比較物件的類的外部實作一個比較器, 當某個自定義的物件需要作比較的時候,把待比較物件和比較器一起傳遞過去就可以實作排序功能,
此外,像String類、包裝類等JDK內置類實作了Comparable介面默認是升序排序,如果要降序排序或指定其他排序規則只能使用Comparator介面,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/38594.html
標籤:Java
上一篇:Java中一個普通的回圈為何從10開始到99連續相乘會得到0?
下一篇:資料結構—二叉排序樹(Java)
