基本數據類型的包裝類Integer, Float, Double,Long,Byte等都實現的Comparable接口,用於列表List或數組arrays的排序
Comparable<Integer>接口方法的實現,對象列表的升序降序接口
我們通過重寫該接口方法,可以對列表進行升序或降序排列。
public int compareTo(T o);
This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.
此接口對實現它的每個類的對象強加一個默認排序。這種排序被稱為類的自然排序,類的compareTo方法被稱為其自然比較方法。
Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort
(and Arrays.sort
).
實現的這個接口的對象list列表或array數組可以使用sort方法讓列表或數組的元素被自動排序
要重寫Compare方法需要滿足下面的要求
比較其兩個參數的順序。當第一個參數小於,等於或大於第二個參數時,返回負整數,零或正整數。 在前面的描述中,符號sgn(expression)表示數學符號函數,該函數定義為根據表達式的值為負,零還是正返回-1、0或1中的一個。 實現者必須確保所有x和y的sgn(compare(x,y))== -sgn(compare(y,x))。 ( 這意味着,當且僅當compare(y,x)引發異常時,compare(x,y)才必須引發異常。) 實現者還必須確保該關系是可傳遞的:((compare(x,y)> 0 )&&(compare(y,z)> 0))意味着compare(x,z)> 0。 最后,實現者必須確保compare(x,y)== 0意味着所有z的sgn(compare(x,z))== sgn(compare(y,z))。 通常是這種情況,但並非嚴格要求(compare(x,y)== 0)==(x.equals(y))。 一般而言,任何違反此條件的比較器都應明確指出這一事實。推薦的語言是“注意:此比較器強加與等號不一致的順序”。
上面的解釋翻譯過來是,
要滿足
int compare(T o1, T o2);
升序:o1>o2 返回1 並且 o1<o2 返回-1, o1==o2 返回0
降序:o1>o2 返回-1 並且 o1<o2 返回1, o1==o2 返回0
上面的條件必須滿足要求才能按照設想的方式正確排序
例如
List<String> orderRule = new ArrayList<>(Arrays.asList("北京", "上海","廣州")); List<String> list = new ArrayList<>(Arrays.asList("天津","", "海南", "上海","廣州","北京")); //根據規則升序排序 countDtoList.sort(new Comparator<String>() { @Override public int compare(String dto1, String dto2){ if (StringUtils.isBlank(dto2)) { //空名稱放最后面 return -1; } if (StringUtils.isBlank(dto1)) { //空名稱放最后面 return 1; } int i1 = orderRule.indexOf(dto1); int i2 = orderRule.indexOf(dto2); // 如果不在規則范圍內的數據放到后面,則要保證 // 如果1在,2不在,返回-1,如果1不在,2在,返回1。 if (i2 < 0 && i1 >= 0) { return -1; } if (i1 < 0 && i2 >= 0) { return 1; } return i1 - i2; } }
只需要實現compareTo()方法即可
public int compareTo(){}這個比較方法,,
如果要將對象列表進行升序排序,則第i個元素和第i+1元素 要滿足a[i]>a[i+1] 返回1 a[i]<a[i+1] 返回-1 a[i]=a[i+1] 返回0
如果要將對象列表進行降序排序 要滿足 a[i]>a[i+1] 返回-1 a[i]<a[i+1] 返回1 a[i]=a[i+1] 返回0
Collections.sort方法實現的就是按照此比較的東西排列 升序(從小到大): if(price < o.price){ return -1; } if(price > o.price){ return 1; } 降序(從大到小): if(price < o.price){ return 1; } if(price > o.price){ return -1; }
//將對象按價格進行升序排序 @Override public int compareTo(flower o) { //首先比較price,如果price相同返回0 if(price < o.price){ return -1; } if(price > o.price){ return 1; } return 0; }
為什么升序 返回值為1時,是n的值要大於n+1的值,而返回值為-1時n的值要小於n+1呢?
這個要查看源碼才可以知道原理。(不好奇的可以不看哦^~^)
由於這個List.sort()這個排序方法時使用二分排序,源碼如下,
while (left < right) { int mid = (left + right) >>> 1; if (pivot.compareTo(a[mid]) < 0) right = mid; else left = mid + 1; }
這個值是和已排序的數據的中間的數據進行比較,provot.compareTo(a[mid])
注意看,上面的a[mid]是作為比較方法的參數。
當小於0,也就是值為-1時,是我們要插入的數據作為調用方,
小於0時,該數據插入到前面,
大於0時,數據插入到后面
思維慣性以為升序就是第一個元素比第二個元素小。obj1.compareTo(Object obj2)
即obj1=2是第一個元素,obj2=8是第二個元素
那么我們升序時,如果obj1小於obj2,返回值為-1,則會將obj2插入到obj1前面,,排序前【2, 8】這樣排序完后卻變成了,,【8, 2】
這跟我們想要的升序數據不一樣,
原因是java的二分法進行比較了是,,obj2.compareTo(obj1),,與我們想的剛好相反,
所以我們返回的值取反就可以變成升序了,
如這個消費類,,只給出部分代碼
public class ConsumInfo implements Comparable<ConsumInfo> { public double price;
public String name;
public Consuminfo(double price, String name){
this.price = price;
this.name = name;
} @Override public int compareTo(ConsumInfo o) { //首先比較price,如果price相同 if(price < o.price){ return -1; } if(price > o.price){ return 1; } return 0; } }
ConsumInfo consumInfo1 = new ConsumInfo("consumInfo1", 400.0); ConsumInfo consumInfo2 = new ConsumInfo("consumInfo2", 200.0);
List<ConsumInfo> list = new ArrayList<ConsumInfo>(); list.add(consumInfo1); list.add(consumInfo2); System.out.println("排序前:"); for(ConsumInfo consumInfo : list ){ System.out.println(consumInfo); } Collections.sort(list);//排序 System.out.println("排序后:");//排序后 for(ConsumInfo consumInfo :list){ System.out.println(consumInfo); }
控制台輸出信息為:
排序前: ConsumInfo [name=consumInfo1, price=400.0] ConsumInfo [name=consumInfo2, price=200.0] 排序后: ConsumInfo [name=consumInfo2, price=200.0] ConsumInfo [name=consumInfo1, price=400.0]
上面是最簡單的兩個元素進行排序,
第一次,往已排序列表中插入第一個元素,即數組中只有一個已排好序的元素,a[0] = consumInfo1
第二次時,left為0,right為1,進入while循環中,
mid=0,privot=consumInfo2
即consumInfo2.comparTo(a[0])
當方法的返回值小於0時,consumInfo2會插入在consumInfo1之前,
大於0時,會在consumInfo1之后
進行比較時,consumInfo2.price<consumInfo1.price 返回值小於0,也就是consumInfo1的值比較大,插入在1之前