Comparable 和 Comparator 都是用來實現集合中元素的比較、排序的。
只是 Comparable 是在集合內部定義的方法實現的排序,而Comparator 是在集合外部實現的排序,
所以,如想實現排序,就需要在集合外定義 Comparator 接口的方法或在集合內實現 Comparable 接口的方法。
Comparator位於包java.util下,而Comparable位於包 java.lang下
一.Comparable 是一個對象,本身就已經支持自比較所需要實現的接口(如 String、Integer 自己就可以完成比較大小操作,已經實現了Comparable接口)
自定義的類要在加入list容器中后能夠排序,可以實現Comparable接口,在用Collections類的sort方法排序時,如果不指定Comparator,那么就以自然順序排序,這里的自然順序就是實現Comparable接口設定的排序方式。
二.Comparator 是一個專用的比較器,當這個對象不支持自比較或者自比較函數不能滿足你的要求時,你可以寫一個比較器來完成兩個對象之間大小的比較。
可以說一個是自已完成比較,一個是外部程序實現比較的差別而已。
用 Comparator 是策略模式(strategy design pattern),就是不改變對象自身,而用一個策略對象(strategy object)來改變它的行為。
1.Comparable用法示例:
需求:
每一個學生都有對應的歸屬地。
學生Student,地址String
學生屬性:姓名,年齡
注意:姓名和年齡相同的視為同一個學生,保證學生的唯一性。
1.描述學生。
2.定義map容器,將學生作為鍵,地址作為值。存入。
3.獲取map集合中的元素。
A.(代碼MapTest.java)
package com.zlc.collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
class Student6 implements Comparable<Student6>{
private String name;
private int age;
public Student6(String name, int age) {
super();
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;
}
public String toString(){
return "姓名:"+name+"-->年齡:"+age;
}
//復寫hashCode()和equals()方法
public int hashCode() {
return name.hashCode()+age*34;
}
public boolean equals(Object obj) {
if(!(obj instanceof Student6)) {
throw new ClassCastException("類型不匹配-->不是學生對象");
}
Student6 s = (Student6) obj;
return this.name.equals(s.name) && this.age == s.age;
}
@Override
public int compareTo(Student6 o) {
int num = new Integer(this.age).compareTo(new Integer(o.age));
if(num == 0){
return this.name.compareTo(o.name);
}
return num;
}
}
public class MapTest {
public static void main(String[] args) {
HashMap<Student6,String> hm = new HashMap<Student6,String>();//注:HashMap是無序存放的。
hm.put(new Student6("xiaozhou",21), "商丘");
hm.put(new Student6("xiaozhou",21), "南陽");//此鍵值與上面的相同,會將上面的value覆蓋
hm.put(new Student6("xiaowang",22), "新鄉");
hm.put(new Student6("xiaochen",20), "鄭州");
hm.put(new Student6("xiaoliu",19), "開封");
//第一種取出方式 keySet
Set<Student6> keySet = hm.keySet();//取出鍵集
Iterator<Student6> it = keySet.iterator();
while(it.hasNext()){
Student6 stu = it.next();//取得學生對象stu
String addr = hm.get(stu);//注:取出stu對應的地址addr,地址在HashMap里面,用hm取出
System.out.println(stu+" ...居住地址:"+addr);//這里的stu就會自動調用 Student6中的toString()方法
}
System.out.println("---------------------------");
//第二種取出方式 entrySet
Set<Map.Entry<Student6, String>> entrySet = hm.entrySet();
Iterator<Map.Entry<Student6, String>> iter = entrySet.iterator();
while(iter.hasNext()){
Map.Entry<Student6, String> me = iter.next();
Student6 stu = me.getKey();
String addr = me.getValue();
System.out.println(stu+" ...居住地址:"+addr);//這里的stu就會自動調用 Student6中的toString()方法
}
}
}
2.Comparator用法(其中也用到了Comparable,順便比較一下。)
需求一:(在不使用Comparator的情況下)
對學生對象的年齡進行升序排序。
因為數據是以鍵值對形式存在的。
所以要使用可以排序的Map集合。TreeMap
需求二:(在使用Comparator的情況下)
先對學生對象的姓名進行升序排序,再按年齡升序。
B.(代碼MapTest2.java)
package com.zlc.collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
class Student7 implements Comparable<Student7> {//除了要重寫Object對象的方法之外,還要實現Comparable接口的比較方法
private String name;
private int age;
public Student7(String name, int age) {
super();
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 boolean equals(Object obj) {
if(!(obj instanceof Object)){
// return false;
throw new ClassCastException("類型不匹配,不是學生對象");
}
Student7 stu = (Student7) obj;
return this.name.equals(stu.name) && this.age == stu.age;
}
@Override
public int hashCode() {
// return super.hashCode();
return name.hashCode()+age*17;
}
@Override
public String toString() {
return "name: "+name+"-->age: "+age;
}
@Override//重寫比較方法
public int compareTo(Student7 s) {
int num = new Integer(this.age).compareTo(new Integer(s.age));//按年齡從小到大進行排序
if(num == 0){//如果年齡相同,再比較姓名,(姓名按Unicode編碼升序排序)
return this.name.compareTo(s.name);
}
return num;
}
}
class StuNameComparator implements Comparator<Student7>{//在同時使用Comparable和Comparator的情況下,如果實現了比較器接口進行比較
@Override
public int compare(Student7 s1, Student7 s2) {
int num = s1.getName().compareTo(s2.getName());//按姓名排序
if(num == 0){//如果名字相同,再比較年齡(如果年齡又相同,則不能加入到TreeMap集合中去)
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
}
return num;
}
}
public class MapTest2 {
public static void main(String[] args) {
/*
* TreeMap(Comparator<? super K> comparator)
構造一個新的、空的樹映射,該映射根據給定比較器進行排序。
* */
TreeMap<Student7,String> tm = new TreeMap<Student7,String>(new StuNameComparator());
tm.put(new Student7("zhangsan",21), "北京");
tm.put(new Student7("lisi",19), "上海");
tm.put(new Student7("wangwu",24), "深圳");
tm.put(new Student7("wangwu",18), "開封");
tm.put(new Student7("xiaohuan",22), "商丘");
tm.put(new Student7("xiaocheng",22), "新鄉");
tm.put(new Student7("xiaocheng",22), "鄭州");//如果該映射以前包含此鍵的映射關系,那么將替換舊值。
tm.put(new Student7("xiaohuan",22), "商丘");
Set<Map.Entry<Student7,String>> entrySet = tm.entrySet();
Iterator<Map.Entry<Student7, String>> it = entrySet.iterator();
while(it.hasNext()){
Map.Entry<Student7, String> me = it.next();
Student7 st = me.getKey();
String addr = tm.get(st);//通過對應的st獲得對應的地址
System.out.println(st+" ...居住地址:"+addr);
}
}
}
說明:
在排序時,如果不是調用sort方法,相要直接比較兩個對象的大小,如下:
Comparator定義了倆個方法,分別是 int compare(T o1, T o2)和 boolean equals(Object obj),
用於比較兩個Comparator是否相等
true only if the specified object is also a comparator and it imposes the same ordering as this comparator.
有時在實現Comparator接口時,並沒有實現equals方法,可程序並沒有報錯,原因是實現該接口的類也是Object類的子類,而Object類已經實現了equals方法
Comparable接口只提供了 int compareTo(T o)方法,也就是說假如我定義了一個Person類,這個類實現了 Comparable接口,那么當我實例化Person類的person1后,我想比較person1和一個現有的Person對象person2的大小時,我就可以這樣來調用:person1.comparTo(person2),通過返回值就可以判斷了;而此時如果你定義了一個 PersonComparator(實現了Comparator接口)的話,那你就可以這樣:PersonComparator comparator= new PersonComparator();
comparator.compare(person1,person2);。
