Comparable&Comoarator
1、内置引用数据类型比较(常用)
1.1 Comparable
1、整数、小数Integer Float Double 直接比较基本数据类型的大小
2、字符:比较的Unicode码只差
3、字符串:
1)如果其中一个是另外一个其实开始的子传,返回长度子差
2)否则返回第一个不相等的Unicode码之差
4、java.util.Date:根据日期的长整形数比较
例1:
1 /** 2 * 引用数据类型的排序 3 * @author qjc 4 * 5 * 2016-3-10 6 */ 7 public class ComparableDemo { 8 /** 9 * 数组排序(使用泛型方法) 10 * @param arr 11 */ 12 public static <T extends Comparable<T>> void sort(T[] arr){ 13 boolean sortede = true; //有序标示则不用比较 14 for (int i = 0; i < arr.length-1; i++) { 15 for (int j = 0; j < arr.length-1-i; j++) { 16 sortede = true; 17 if(((Comparable)arr[j]).compareTo(arr[j+1]) > 0){ 18 T temp = arr[j]; 19 arr[j] = arr[j+1]; 20 arr[j+1] = temp; 21 sortede = false; 22 } 23 if(sortede){ //减少趟数 24 break; 25 } 26 } 27 } 28 } 29 public static void main(String[] args) { 30 String[] arr = {"abc","ab","a"}; 31 sort(arr); 32 for(String s : arr){ 33 System.out.println(s); 34 } 35 //结果: a ab abc 36 } 37 }
1.2 Comparator
提供排序的比较器,业务比较器
实现java.util.Comparator接口
重写public intcompare(T o1,T o2)
作用:
解耦:独立于实体类
方便:便于应用各种排序规则
例2:
1 /** 2 * 排序规则的业务类 3 * @author qjc 4 * 5 * 2016-3-10 6 */ 7 public class StringComp implements java.util.Comparator { 8 /** 9 * 按长度比较大小 10 * 正数: >0 11 * 负数: <0 12 * 0 :== 13 */ 14 @Override 15 public int compare(Object o1, Object o2) { 16 int len1 = ((String) o1).length(); 17 int len2 = ((String) o2).length(); 18 return len1 - len2; 19 } 20 } 21 22 /** 23 * Comparator排序 24 * @author qjc 25 * 26 * 2016-3-10 27 */ 28 public class ComparatorDemo { 29 /** 30 * 数组的排序(升序)+Comparator接口 31 * @param arr 32 * @param comm 33 */ 34 public static <T> void sort(Object[] arr,Comparator<T> comm){ 35 boolean sorted = true; 36 for (int i = 0; i < arr.length-1; i++) { 37 for (int j = 0; j < arr.length-1-i; j++) { 38 if(comm.compare((T)arr[j], (T)arr[j+1]) > 0){ 39 Object temp = arr[j]; 40 arr[j] = arr[j+1]; 41 arr[j+1] = temp; 42 sorted = false; 43 } 44 if(sorted){ 45 break; 46 } 47 } 48 } 49 } 50 @Test 51 public void testSort(){ 52 String[] arr = {"dss","fdss","fefeef"}; 53 sort(arr, new StringComp()); 54 System.out.println(Arrays.toString(arr)); 55 //输出结果: [dss, fdss, fefeef] 56 } 57 }
1.3 Collections之排序
Collections工具类,此类完全由在collection 上进行操作或返回 collection 的静态方法组成。
提供了大量便于处理容器的方法
关于排序:
1、public static <T extends Comparable<?super T>> void sort(List<T> list)
2、public static<T> void sort(List<T> list,Comparator<? super T> c)
2、引用类型(自定义)
2.1 Comparable
按业务规则排序:
1、实体类:java.lang.Comparable + compareTo
例3:
新闻信息排序:按时间(第一排序)、点击量(第二排序)、标题(第三排序)
/** * 新闻条目实体类 * @author qjc * * 2016-3-10 */ public class NewItem implements java.lang.Comparable<NewItem>{ //标题 private String title; //点击量 private int hits; //时间 private Date pubTime; //时间降序(第一排序) + 点击量升序(第二排序) + 标题降序 @Override public int compareTo(NewItem ntm) { int result = 0; //比较时间 result = - this.pubTime.compareTo(ntm.pubTime); //降序 if(0 == result){ //点击量 result = this.hits - ntm.hits; //升序 //点击量相同 if(0 == result){ //标题 result = - this.title.compareTo(ntm.title); //降序 } } return result; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("标题:").append(this.title); sb.append("时间:").append(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.pubTime)); sb.append("点击量:").append(this.hits).append("\n"); return sb.toString(); } //getter and setter... } /** * * @author qjc * * 2016-3-10 */ public class NewItemApp { @Test public void test(){ List<NewItem> news = new ArrayList<>(); news.add(new NewItem("袁贵仁:十三五期间9年义务教育不会延长",100, new Date(System.currentTimeMillis()-1000*60*60))); news.add(new NewItem("沪指收跌2.02%危及2800点 分析:三因素影响A股",999, new Date())); news.add(new NewItem("女足回京球迷献吻 盼奥运进四强拿牌",888, new Date(System.currentTimeMillis()+1000*60*60))); System.out.println("排序前:"+news); System.out.println("===================================="); //Collections工具类排序(默认升序) Collections.sort(news); System.out.println("排序后:"+news); } }
输出结果:
排序前:
[标题:袁贵仁:十三五期间9年义务教育不会延长时间:2016-03-10 21:33:28点击量:100
,标题:沪指收跌2.02%危及2800点分析:三因素影响A股时间:2016-03-10 22:33:28点击量:999
,标题:女足回京球迷献吻盼奥运进四强拿牌时间:2016-03-1023:33:28点击量:888
]
====================================
排序后:
[标题:女足回京球迷献吻盼奥运进四强拿牌时间:2016-03-10 23:33:28点击量:888
,标题:沪指收跌2.02%危及2800点分析:三因素影响A股时间:2016-03-10 22:33:28点击量:999
,标题:袁贵仁:十三五期间9年义务教育不会延长时间:2016-03-1021:33:28点击量:100
]
2.2 Comparator
2、业务排序类:java.util.Comparator + compare
优点:
- 解耦:与实体类分类
- 方便:应对多变排序规则
例4:
按商品价格排序
1 /** 2 * 商品类 3 * @author qjc 4 * 5 * 2016-3-10 6 */ 7 public class Goods { 8 //商品名 9 private String name; 10 //收藏量 11 private int fav; 12 //价格 13 private double price; 14 @Override 15 public String toString() { 16 return "商品名:"+this.name+",收藏量"+this.fav+",价格"+this.price+"\n"; 17 } 18 //getter and setter... 19 } 20 21 /** 22 * 按价格排序的业务类(降序) 23 * @author qjc 24 * 25 * 2016-3-10 26 */ 27 public class GoodsPriceComp implements java.util.Comparator<Goods>{ 28 29 @Override 30 public int compare(Goods o1, Goods o2) { 31 return -(o1.getPrice()-o2.getPrice()>0 ? 1 : (o1.getPrice()==o2.getPrice())?0 : -1); 32 } 33 } 34 35 /** 36 * 37 * @author qjc 38 * 39 * 2016-3-10 40 */ 41 public class GoodsApp { 42 @Test 43 public void test(){ 44 List<Goods> list = new ArrayList<>(); 45 list.add(new Goods("iphone 5SE",1800,3888)); 46 list.add(new Goods("iphone 7",1998,5888)); 47 list.add(new Goods("Galaxy S7",2000,4888)); 48 System.out.println("排序前:"+list); 49 //排序 50 Collections.sort(list,new GoodsPriceComp()); 51 System.out.println("排序后:"+list); 52 } 53 }
输出结果:
排序前:
[商品名:iphone 5SE,收藏量1800,价格3888.0
,商品名:iphone 7,收藏量1998,价格5888.0
,商品名:Galaxy S7,收藏量2000,价格4888.0
]
排序后:
[商品名:iphone 7,收藏量1998,价格5888.0
,商品名:Galaxy S7,收藏量2000,价格4888.0
,商品名:iphone 5SE,收藏量1800,价格3888.0
]
3.3 TreeSet和TreeMap集合排序
3.3.1 TreeSet:
数据元素可以排序且不可以重复
- 确保元素实体可以排序
- 排序比较器
publicTreeSet(Compartor<? super E> comparator)
对比Set接口:HashSet,元素必须重写hashcode和equals方法。
去重:比较等于0即重复
例5:使用TreeSet无参构造实体类实现Comparable
/** * 实体类实现Comparable * @author qjc * * 2016-3-11 */ public class Worker implements java.lang.Comparable<Worker>{ //工种 private String type; //工资 private double salary; //按工资升序 @Override public int compareTo(Worker o) { return this.salary>o.salary?1:this.salary==o.salary?0:-1; } //getter and setter.. } /** * 使用Comparable排序 * @author qjc * * 2016-3-11 */ public class TreeSetDemo2 { public static void main(String[] args) { Worker w1 = new Worker("教师",12000); Worker w2 = new Worker("公务员",8000); Worker w3 = new Worker("程序猿",6000); TreeSet<Worker> employeess = new TreeSet<>(); employeess.add(w1); employeess.add(w2); employeess.add(w3); System.out.println(employeess); } }
例6:使用TreeSet带参构造使用Comparator比较器
1 public class Person { 2 private String name; 3 //帅气指数 4 private int handsome; 5 //geter and setter.. 6 } 7 8 /** 9 * 提供解耦方式排序 10 * @author qjc 11 * 12 * 2016-3-11 13 */ 14 public class TreeSetDemo { 15 public static void main(String[] args) { 16 Person p1 = new Person("刘德华", 2000); 17 Person p2 = new Person("梁朝伟", 2200); 18 Person p3 = new Person("鹿晗", 1500); 19 //依次放到TreeSet容器中,使用排序的业务类(内部类) 20 TreeSet<Person> persons = new TreeSet<>( 21 new java.util.Comparator<Person>(){ 22 @Override 23 public int compare(Person o1, Person o2) { 24 //降序 25 return -(o1.getHandsome() - o2.getHandsome()); 26 } 27 } 28 ); 29 //TreeSet 在添加数据时排序 30 persons.add(p1); 31 persons.add(p2); 32 persons.add(p3); 33 System.err.println(persons); 34 } 35 } 36
注意:
在添加数据时排序,数据更改不会影响原来的顺序,不要修改数据,否则可能重复。 ---可以使用final修饰
3.3.2 TreeMap:
- 确保key可以排序
- 提供比较器
publicTreeMap(Comparator<? super K> comparator)
例:与TreeSet同理
总结:
相同点:
Comparable和Comparator都是用来实现集合、数组中元素的比较、排序的
不同点:
1、Comparable是在集合内部定义的方法实现的排序,而Comparator是在集合外部实现的排序,
所以,如想实现排序,就需要在集合外定义 Comparator接口的方法或在集合内实现 Comparable接口的方法。
Comparator位于包java.util下,而Comparable位于包java.lang下
2、Comparable是一个对象,本身就已经支持自比较所需要实现的接口(如Integer、String、Float、Double、Date等底层都实现了Comparable接口 自己就可以完成比较大小操作)
自定义的类要在加入list容器中后能够排序,可以实现Comparable接口,在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序,这里的自然顺序就是实现Comparable接口设定的排序方式,并且是升序。
3、Comparator是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
Comparator 与实体类分类于系统解耦优点,比如说例4按商品排序,如果需要按名称排序(或改升序、降序),只需要在业务类修改,在应变多变规则时方便程序修改和维护。所以推荐使用Comparator。