作者 | TrueDei
責編 | 王曉曼
出品 | CSDN博客
前言
排序是在程序開發中最常用到的,最常見的就是針對一些數字進行排序。而現實中像商品的名字,訂單的日期等進行排序。Java的JDK中就自帶了Comparable接口,那麼來看下這個,如何與面試官對答如流。
拋下 Arrays.sort() 中排序的算法,一起來揭開這層面紗吧。
1、猜一猜
猜測以下代碼的執行結果是什麼?
int[] ints = {50,1,4,8,3};String [] strings = {"q","a","c"};Arrays.sort(ints);for (String val: strings) { System.out.print(val + " ");}System.out.println();for (int i = 0; i < ints.length; i++) { System.out.print(ints[i]+" ");}
好了,現在猜測結束。
你會很快猜到一下內容:
q a c 134850
你可真是一個小能能,厲害的不要不要的。
但是,如果面試官問你:
為什麼 int 數組, String 數組等等,這些可以使用 Arrays.sort() 進行排序呢?
咱們慢慢揭曉這個答案。
先看幾個原始碼:
1、Integer的原始碼
publicfinalclassIntegerextendsNumberimplementsComparable<Integer> { ..... ..... .....publicintcompareTo(Integer anotherInteger){return compare(this.value, anotherInteger.value); }}
2、Short的原始碼
publicfinalclassShortextendsNumberimplementsComparable<Short> { ..... ..... .....publicintcompareTo(Short anotherShort){return compare(this.value, anotherShort.value); }}
3、String的原始碼
publicfinalclassStringimplementsjava.io.Serializable, Comparable<String>, CharSequence{ ..... ..... .....publicintcompareTo(String anotherString){int len1 = value.length;int len2 = anotherString.value.length;int lim = Math.min(len1, len2);char v1[] = value;char v2[] = anotherString.value;int k = 0;while (k < lim) {char c1 = v1[k];char c2 = v2[k];if (c1 != c2) {return c1 - c2; } k++; }return len1 - len2; }}
發現了什麼?
是不是發現了都實現了Comparable接口和compareTo方法。
對,你現在也許知道怎麼去回答面試官這個問題了,因為他們都實現了Comparable接口和compareTo方法。
3、試試真是如此嗎?不信測試一下
新建二個實體類和一個測試類,一個是Student實體類,一個是User實體類,一個是測試類Test。
Student類
為了方便演示,這裡的Student類實現Comparable接口。
package ComparableInterface;/** * @Auther: truedei * @Date: 2020 /20-5-7 20:29 * @Description: */publicclassStudentimplementsComparable<Student>{privateint age;private String name;publicStudent(){ }publicStudent(int age, String name){this.age = age;this.name = name; }publicintgetAge(){return age; }publicvoidsetAge(int age){this.age = age; }public String getName(){return name; }publicvoidsetName(String name){this.name = name; }@Overridepublic String toString(){return"Student{" +"age=" + age +", name='" + name + '\'' +'}'; }@OverridepublicintcompareTo(Student o){returnthis.getAge() - o.getAge(); }}
User類
為了方便演示,這裡的User類不實現Comparable接口。
package ComparableInterface;/** * @Auther: truedei * @Date: 2020 /20-5-7 20:29 * @Description: */publicclassUser{privateint age;private String name;publicUser(){ }publicUser(int age, String name){this.age = age;this.name = name; }publicintgetAge(){return age; }publicvoidsetAge(int age){this.age = age; }public String getName(){return name; }publicvoidsetName(String name){this.name = name; }@Overridepublic String toString(){return"User{" +"age=" + age +", name='" + name + '\'' +'}'; }}
測試類
package ComparableInterface;import java.util.ArrayList;import java.util.Arrays;import java.util.List;/** * @Auther: truedei * @Date: 2020 /20-5-7 20:29 * @Description: */publicclassTest{publicstaticvoidmain(String[] args){ }}
測試1、比較Student類
Student s1 = new Student(19,"張三");Student s2 = new Student(18,"李四");int i = s1.compareTo(s2);if(i>=0){ System.out.println(s1.getName()+"年齡大");}else{ System.out.println(s2.getName()+"年齡大");}
測試結果1:
這個結果也是很容易猜到的,因為Student類實現了Comparable接口,並實現了 compareTo方法。並且是以age做比較的。
張三年齡大
測試2、比較User類
User u1 = new User(12,"王五"); User u2 = new User(22,"趙六");int j = u1.compareTo(u2);if(j>=0){ System.out.println(u1.getName()+"年齡大"); }else{ System.out.println(u2.getName()+"年齡大"); }
測試2的結果:
這個是沒有結果的,因為程序是無法執行的,會報出沒有compareTo這個方法。
原因:
原因很簡單,因為沒有實現Comparable接口。
測試3、對Student類的數組排序
隨便添加進去幾個數據,為了方便理解,我就寫的稍微麻煩了一點。
Student s1 = new Student(19,"張三"); Student s2 = new Student(18,"李四"); Student s3 = new Student(2,"王五"); Student[] students = {s1,s2,s3}; System.out.println("排序前:");for (Student st:students) { System.out.println(st.toString()); } System.out.println();//進行排序 Arrays.sort(students); System.out.println("排序後:");for (Student st:students) { System.out.println(st.toString()); }
測試結果:
是不是有點小驚喜?為什麼可以進行直接排序呢?
沒錯,就是因為實現了那個Comparable接口,而且是根據年齡的大小來排序的。
排序前:Student{age=19, name='張三'}Student{age=18, name='李四'}Student{age=2, name='王五'}排序後:Student{age=2, name='王五'}Student{age=18, name='李四'}Student{age=19, name='張三'}
如果你想從大到小排序怎麼辦?
也很簡單,只需要改變一下compareTo中的方法即可。
修改如下:
@OverridepublicintcompareTo(Student o){// return this.getAge() - o.getAge();return o.getAge()- this.getAge(); }
為了好看,我把三個Student類的數據,修改了一下:
Student s1 = new Student(7,"張三");Student s2 = new Student(18,"李四");Student s3 = new Student(2,"王五");
測試結果:
排序前:Student{age=7, name='張三'}Student{age=18, name='李四'}Student{age=2, name='王五'}排序後:Student{age=18, name='李四'}Student{age=7, name='張三'}Student{age=2, name='王五'}Process finished with exit code 0
測試4、對User類的數組排序
可以先猜測一下,可能排序嗎?
User u1 = new User(12,"王五"); User u2 = new User(22,"趙六"); User u3 = new User(15,"雜七"); User[] users = {u1,u2,u3}; System.out.println("排序前:");for (User user:users) { System.out.println(user.toString()); } System.out.println();//進行排序 Arrays.sort(users); System.out.println("排序後:");for (User user:users) { System.out.println(user.toString()); }
測試結果:
排序前:User{age=12, name='王五'}User{age=22, name='趙六'}User{age=15, name='雜七'}Exception in thread "main" java.lang.ClassCastException: ComparableInterface.User cannot be cast to java.lang.Comparable at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320) at java.util.ComparableTimSort.sort(ComparableTimSort.java:188) at java.util.Arrays.sort(Arrays.java:1246) at ComparableInterface.Test.main(Test.java:54)
提示你:
cannot be cast to java.lang.Comparable
說明:無法轉換成Comparable
那麼就得出結論:
沒有實現Comparable接口的類的數組是無法使用Arrays.sort()進行排序的
改造 User類 進一步測試
稍微改造一下:給User類實現Comparable接口。
1、需求如下
因為User類有年齡和姓名,年齡小的優先。
如果年齡相同,那麼比較姓名,按姓名的ascii碼值來排序,例如:a-b-c
2、修改User類
package ComparableInterface;/** * @Auther: truedei * @Date: 2020 /20-5-7 20:29 * @Description: */publicclassUserimplementsComparable<User>{privateint age;private String name;publicUser(){ }publicUser(int age, String name){this.age = age;this.name = name; }publicintgetAge(){return age; }publicvoidsetAge(int age){this.age = age; }public String getName(){return name; }publicvoidsetName(String name){this.name = name; }@Overridepublic String toString(){return"User{" +"age=" + age +", name='" + name + '\'' +'}'; }@OverridepublicintcompareTo(User o){//年齡從小到大if(this.getAge() - o.getAge() > 0){return1; }elseif(this.getAge() - o.getAge() == 0){returnthis.getName().compareTo(o.getName()); }return -1; }}
重點是:
可以看到年齡是從小到大的對比如果this.年齡 - o.年齡 == 0 說明相等,那麼就比較名字@Overridepublic int compareTo(User o) {//年齡從小到大if(this.getAge() - o.getAge() > 0){return1; }elseif(this.getAge() - o.getAge() == 0){returnthis.getName().compareTo(o.getName()); }return-1;}
3、測試
為了方便理解,我把姓名修改成了a,e,s,q,d,g這些字母
為了比較好說明,我找了一個比較簡潔的ascii碼錶:
我們拿a、b、y做為姓名來測試:
System.out.println("a="+(int)'a');System.out.println("b="+(int)'b');System.out.println("y="+(int)'y');
結果:
97<98<121
a<b<y
a=97b=98y=121
正式代碼:
User u1 = new User(12,"b"); User u2 = new User(22,"y"); User u3 = new User(22,"a"); User[] users = {u1,u2,u3}; System.out.println("排序前:");for (User user:users) { System.out.println(user.toString()); } System.out.println();//進行排序 Arrays.sort(users); System.out.println("排序後:");for (User user:users) { System.out.println(user.toString()); }
測試結果:
排序前:User{age=12, name='b'}User{age=22, name='y'}User{age=22, name='a'}排序後:User{age=12, name='b'}User{age=22, name='a'}User{age=22, name='y'}
版權聲明:本文為CSDN博主「TrueDei」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本聲明。
原文連結:
https://truedei.blog.csdn.net/article/details/105981691