Comparable與Comparator


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);。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM