java中的Comparable與Comparator
以前一直對(duì)Comparable與Comparator的區(qū)別比較模糊,今天抽空好好的了解了下,發(fā)現(xiàn)收獲蠻大的,所以來(lái)跟大家分享下,如果有不對(duì)的地方還請(qǐng)指正。
先來(lái)看看這2個(gè)接口在jdk API種的解釋?zhuān)?br /> Comparable:此接口強(qiáng)行對(duì)實(shí)現(xiàn)它的每個(gè)類(lèi)的對(duì)象進(jìn)行整體排序。這種排序被稱(chēng)為類(lèi)的自然排序,類(lèi)的 compareTo 方法被稱(chēng)為它的自然比較方法。
實(shí)現(xiàn)此接口的對(duì)象列表(和數(shù)組)可以通過(guò) Collections.sort(和 Arrays.sort)進(jìn)行自動(dòng)排序。實(shí)現(xiàn)此接口的對(duì)象可以用作有序映射中的鍵或有序集合中的元素,無(wú)需指定比較器。
Comparator:強(qiáng)行對(duì)某個(gè)對(duì)象 collection 進(jìn)行整體排序 的比較函數(shù)。可以將 Comparator 傳遞給 sort 方法(如 Collections.sort 或 Arrays.sort),從而允許在排序順序上實(shí)現(xiàn)精確控制。還可以使用 Comparator 來(lái)控制某些數(shù)據(jù)結(jié)構(gòu)(如有序 set或有序映射)的順序,或者為那些沒(méi)有自然順序的對(duì)象 collection 提供排序。
實(shí)現(xiàn)此接口的對(duì)象可以用作有序映射中的鍵或有序集合中的元素,無(wú)需指定比較器。從這句話可以看出我們之所以可以對(duì)數(shù)字或者字母進(jìn)行排序而不需制定比較器,是因?yàn)樵贘DK中他們已經(jīng)實(shí)現(xiàn)了Comparable接口,所以通過(guò)Collections.sort和 Arrays.sort方法可以給他們按自然順序排序,當(dāng)我們要對(duì)一個(gè)自定義對(duì)象進(jìn)行排序的時(shí)候,也可以實(shí)現(xiàn)Comparable接口,實(shí)現(xiàn)它的compareTo方法。
如果要用Comparator接口來(lái)實(shí)現(xiàn)對(duì)象在集合中的排序,直接在對(duì)象中實(shí)現(xiàn)Comparator接口是不起作用的(針對(duì)TreeSet,下文中一樣,其它的集合類(lèi)還沒(méi)發(fā)現(xiàn)可以在對(duì)象中實(shí)現(xiàn)Comparator來(lái)進(jìn)行排序),需要另外新建一個(gè)類(lèi)實(shí)現(xiàn)Comparator接口,然后通過(guò)集合的構(gòu)造函數(shù)傳到集合中,才會(huì)起作用,直接看TreeSet的源代碼吧。
利用Arrays.sort(T[] a, Comparator<? super T> c)可以對(duì)數(shù)組進(jìn)行排序,利用Collections.sort(List<T> list, Comparator<? super T> c) 可以對(duì)實(shí)現(xiàn)了list接口的集合進(jìn)行排序,如果需要對(duì)Set進(jìn)行排序,可以先把Set轉(zhuǎn)換成ArrayList,然后再進(jìn)行排序。
先來(lái)看看這2個(gè)接口在jdk API種的解釋?zhuān)?br /> Comparable:此接口強(qiáng)行對(duì)實(shí)現(xiàn)它的每個(gè)類(lèi)的對(duì)象進(jìn)行整體排序。這種排序被稱(chēng)為類(lèi)的自然排序,類(lèi)的 compareTo 方法被稱(chēng)為它的自然比較方法。
實(shí)現(xiàn)此接口的對(duì)象列表(和數(shù)組)可以通過(guò) Collections.sort(和 Arrays.sort)進(jìn)行自動(dòng)排序。實(shí)現(xiàn)此接口的對(duì)象可以用作有序映射中的鍵或有序集合中的元素,無(wú)需指定比較器。
Comparator:強(qiáng)行對(duì)某個(gè)對(duì)象 collection 進(jìn)行整體排序 的比較函數(shù)。可以將 Comparator 傳遞給 sort 方法(如 Collections.sort 或 Arrays.sort),從而允許在排序順序上實(shí)現(xiàn)精確控制。還可以使用 Comparator 來(lái)控制某些數(shù)據(jù)結(jié)構(gòu)(如有序 set或有序映射)的順序,或者為那些沒(méi)有自然順序的對(duì)象 collection 提供排序。
實(shí)現(xiàn)此接口的對(duì)象可以用作有序映射中的鍵或有序集合中的元素,無(wú)需指定比較器。從這句話可以看出我們之所以可以對(duì)數(shù)字或者字母進(jìn)行排序而不需制定比較器,是因?yàn)樵贘DK中他們已經(jīng)實(shí)現(xiàn)了Comparable接口,所以通過(guò)Collections.sort和 Arrays.sort方法可以給他們按自然順序排序,當(dāng)我們要對(duì)一個(gè)自定義對(duì)象進(jìn)行排序的時(shí)候,也可以實(shí)現(xiàn)Comparable接口,實(shí)現(xiàn)它的compareTo方法。
1 @Override
2 public int compareTo(User user) {
3 if(this == null || user == null || this.getAge() > user.getAge())
4 return 1;
5 if(this.getAge() < user.getAge())
6 return -1;
7 return 0;
8 }
如果該對(duì)象小于、等于或大于指定對(duì)象,則分別返回負(fù)整數(shù)、零或正整數(shù),可以通過(guò)返回的值來(lái)控制對(duì)象在集合的位置,可以按年齡的小到大排序,也可以按年齡的大到小排序。2 public int compareTo(User user) {
3 if(this == null || user == null || this.getAge() > user.getAge())
4 return 1;
5 if(this.getAge() < user.getAge())
6 return -1;
7 return 0;
8 }
如果要用Comparator接口來(lái)實(shí)現(xiàn)對(duì)象在集合中的排序,直接在對(duì)象中實(shí)現(xiàn)Comparator接口是不起作用的(針對(duì)TreeSet,下文中一樣,其它的集合類(lèi)還沒(méi)發(fā)現(xiàn)可以在對(duì)象中實(shí)現(xiàn)Comparator來(lái)進(jìn)行排序),需要另外新建一個(gè)類(lèi)實(shí)現(xiàn)Comparator接口,然后通過(guò)集合的構(gòu)造函數(shù)傳到集合中,才會(huì)起作用,直接看TreeSet的源代碼吧。
1 int cmp;
2 Entry<K,V> parent;
3 // split comparator and comparable paths
4 Comparator<? super K> cpr = comparator;
5 if (cpr != null) {
6 do {
7 parent = t;
8 cmp = cpr.compare(key, t.key);
9 if (cmp < 0)
10 t = t.left;
11 else if (cmp > 0)
12 t = t.right;
13 else
14 return t.setValue(value);
15 } while (t != null);
16 }
17 else {
18 if (key == null)
19 throw new NullPointerException();
20 Comparable<? super K> k = (Comparable<? super K>) key;
21 do {
22 parent = t;
23 cmp = k.compareTo(t.key);
24 if (cmp < 0)
25 t = t.left;
26 else if (cmp > 0)
27 t = t.right;
28 else
29 return t.setValue(value);
30 } while (t != null);
31 }
32 Entry<K,V> e = new Entry<K,V>(key, value, parent);
33 if (cmp < 0)
34 parent.left = e;
35 else
36 parent.right = e;
37 fixAfterInsertion(e);
38 size++;
39 modCount++;
40 return null;
comparator是在構(gòu)造TreeSet對(duì)象的時(shí)候傳進(jìn)去的,所以如果comparator為null,它就會(huì)按照Comparable排序,如果對(duì)象沒(méi)有實(shí)現(xiàn)Comparable接口,就會(huì)拋出異常,所以到現(xiàn)在為止,我還沒(méi)發(fā)現(xiàn)直接在對(duì)象中實(shí)現(xiàn)comparator接口可以排序的。看完這段代碼我們還可以發(fā)現(xiàn)如果對(duì)象沒(méi)有實(shí)現(xiàn)Comparable接口或者沒(méi)有通過(guò)構(gòu)造一個(gè)以comparator為排序的集合,是不能在TreeSet或TreeMap中使用的(實(shí)際TreeSet就是通過(guò)TreeMap實(shí)現(xiàn)的,不了解的可以看TreeSet的源代碼),最多只能添加一個(gè)對(duì)象root。2 Entry<K,V> parent;
3 // split comparator and comparable paths
4 Comparator<? super K> cpr = comparator;
5 if (cpr != null) {
6 do {
7 parent = t;
8 cmp = cpr.compare(key, t.key);
9 if (cmp < 0)
10 t = t.left;
11 else if (cmp > 0)
12 t = t.right;
13 else
14 return t.setValue(value);
15 } while (t != null);
16 }
17 else {
18 if (key == null)
19 throw new NullPointerException();
20 Comparable<? super K> k = (Comparable<? super K>) key;
21 do {
22 parent = t;
23 cmp = k.compareTo(t.key);
24 if (cmp < 0)
25 t = t.left;
26 else if (cmp > 0)
27 t = t.right;
28 else
29 return t.setValue(value);
30 } while (t != null);
31 }
32 Entry<K,V> e = new Entry<K,V>(key, value, parent);
33 if (cmp < 0)
34 parent.left = e;
35 else
36 parent.right = e;
37 fixAfterInsertion(e);
38 size++;
39 modCount++;
40 return null;
1 Entry<K,V> t = root;
2 if (t == null) {
3 // TBD:
4 // 5045147: (coll) Adding null to an empty TreeSet should
5 // throw NullPointerException
6 //
7 // compare(key, key); // type check
8 root = new Entry<K,V>(key, value, null);
9 size = 1;
10 modCount++;
11 return null;
12 }
comparator的用處在于可以通過(guò)不同的comparator實(shí)現(xiàn)類(lèi),在不通的條件下對(duì)在集合中的對(duì)象按不同的順序進(jìn)行排序,這樣充分利用了java的多態(tài),也讓我們?cè)诰幊痰倪^(guò)程中能很好的解耦。2 if (t == null) {
3 // TBD:
4 // 5045147: (coll) Adding null to an empty TreeSet should
5 // throw NullPointerException
6 //
7 // compare(key, key); // type check
8 root = new Entry<K,V>(key, value, null);
9 size = 1;
10 modCount++;
11 return null;
12 }
利用Arrays.sort(T[] a, Comparator<? super T> c)可以對(duì)數(shù)組進(jìn)行排序,利用Collections.sort(List<T> list, Comparator<? super T> c) 可以對(duì)實(shí)現(xiàn)了list接口的集合進(jìn)行排序,如果需要對(duì)Set進(jìn)行排序,可以先把Set轉(zhuǎn)換成ArrayList,然后再進(jìn)行排序。
1 Set<User> users = new TreeSet<User>(new UserComparator());
2 User user = new User();
3 user.setAge(24);
4 user.setName("wenbo");
5 users.add(user);
6 User user1 = new User();
7 user1.setAge(23);
8 user1.setName("wenbo1");
9 users.add(user1);
10 List<User> useList = new ArrayList<User>(users);
11 Collections.sort(useList,new UserMaxComparator());
通過(guò)上面的分析,不知道大家有沒(méi)有理解這2個(gè)接口,我認(rèn)為如果需要對(duì)一個(gè)對(duì)象進(jìn)行排序,建議使用comparator接口,因?yàn)樗`活,或許效率更高。2 User user = new User();
3 user.setAge(24);
4 user.setName("wenbo");
5 users.add(user);
6 User user1 = new User();
7 user1.setAge(23);
8 user1.setName("wenbo1");
9 users.add(user1);
10 List<User> useList = new ArrayList<User>(users);
11 Collections.sort(useList,new UserMaxComparator());
posted on 2011-11-26 17:44 樂(lè)隨心動(dòng) 閱讀(376) 評(píng)論(0) 編輯 收藏 所屬分類(lèi): java基礎(chǔ)