在Java集合的学习中,我们明白了:

    看到tree,可以按顺序进行排列,就要想到两个接口。Comparable(集合中元素实现这个接口,元素自身具备可比性),Comparator(比较器,传入容器构造方法中,容器具备可比性)。

那么Comparable和Comparator有什么区别呢?

1.  Comparable---接口(集合中元素实现此接口,元素具有可比性)

  Comparable可以认为是一个内比较器,实现了Comparable接口的类有一个特点,就是这些类是可以和自己比较的,至于具体和另一个实现了Comparable接口的类如何比较,则依赖compareTo方法的实现,compareTo方法也被称为自然比较方法。如果开发者add进入一个Collection的对象想要Collections的sort方法帮你自动进行排序的话,那么这个对象必须实现Comparable接口。compareTo(Object o)方法的返回值是int,且此方法只有一个参数,返回值有三种情况:

1、返回正整数

2、返回0

3、返回负整数

  可以这么理解:返回1表示当前元素排在与之对比的元素后面,返回-1表示当前元素排在与之对比的元素前面,返回0表示不排序(按其原顺序排列)。(其实并不是1,-1,0;只要是正数负数和0就可以进行区分)。

  元素自身可以理解为基准,而参数上的obj可以理解为与之对比的元素。

1.比如我们想比较人的时候按年龄倒序排列

  思路:实现上面接口,如果与之对比的元素年龄比他大,排在他前面(返回负数),否则排在他后面(返回正数)。

例如:

public class Person implements Comparable<Person> {

    private int age;
private String name; public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public int compareTo(Person comparedUser) {
// 返回负数表示this对象排在comparedUser前面
if (this.age > comparedUser.getAge()) {
return -1;
} // 返回正数表示this对象排在comparedUser后面
if (this.age < comparedUser.getAge()) {
return 1;
} return 0;
} public Person(int age, String name) {
super();
this.age = age;
this.name = name;
} @Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
} }

测试:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List; public class Test1 {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person(20, "张三"));
list.add(new Person(22, "李四"));
list.add(new Person(19, "王五"));
list.add(new Person(19, "张是"));
list.add(new Person(17, "开发"));
list.add(new Person(29, "看")); Collections.sort(list);
for(Person p : list){
System.out.println(p);
}
}
}

结果:

Person [age=29, name=看]
Person [age=22, name=李四]
Person [age=20, name=张三]
Person [age=19, name=王五]
Person [age=19, name=张是]
Person [age=17, name=开发]

2.按照上面的思路我们写一个按年龄正序排列

修改上面的compareTo方法:

    @Override
public int compareTo(Person comparedUser) {
// 返回负数表示this对象排在comparedUser前面
if (this.age < comparedUser.getAge()) {
return -1;
} // 返回正数表示this对象排在comparedUser后面
if (this.age > comparedUser.getAge()) {
return 1;
} return 0;

测试代码还是上面代码,查看结果:

Person [age=17, name=开发]
Person [age=19, name=王五]
Person [age=19, name=张是]
Person [age=20, name=张三]
Person [age=22, name=李四]
Person [age=29, name=看]

3.将自身具有可比性的元素存入TreeSet或者TreeMap进行查看(TreeSet会自动将元素排序,元素作为key的时候TreeMap会根据key排序)

Person.java

public class Person implements Comparable<Person> {

    private int age;
private String name; public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public int compareTo(Person comparedUser) {
// 返回负数表示this对象排在comparedUser前面
if (this.age > comparedUser.getAge()) {
return -1;
} // 返回正数表示this对象排在comparedUser后面
if (this.age < comparedUser.getAge()) {
return 1;
} return 0;
} public Person(int age, String name) {
super();
this.age = age;
this.name = name;
} @Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
} }

测试代码:

package cn.qlq.test;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet; public class TreeSetTest {
public static void main(String[] args) {
Set<Person> list = new TreeSet<>();
list.add(new Person(20, "张三"));
list.add(new Person(22, "李四"));
list.add(new Person(19, "王五"));
list.add(new Person(19, "张是"));
list.add(new Person(17, "开发"));
list.add(new Person(29, "看")); for(Person p : list){
System.out.println(p);
}
System.out.println("-----------------------------"); //作为key会将key排序
Map map = new TreeMap();
map.put(new Person(20, "张三"), "1");
map.put(new Person(22, "李四"), "2");
map.put(new Person(19, "张三"), "3");
map.put(new Person(25, "哇塞"), "4");
for(Object key :map.keySet()){
System.out.println(key+"\t"+map.get(key));
} System.out.println("-----------------------------");
//作为value无效
Map map2 = new TreeMap();
map2.put("1",new Person(20, "张三"));
map2.put("2",new Person(22, "李四"));
map2.put("3",new Person(19, "张三"));
map2.put("4",new Person(25, "哇塞"));
for(Object key :map2.keySet()){
System.out.println(key+"\t"+map2.get(key));
}
}
}

结果:

Person [age=29, name=看]
Person [age=22, name=李四]
Person [age=20, name=张三]
Person [age=19, name=王五]
Person [age=17, name=开发]
-----------------------------
Person [age=25, name=哇塞] 4
Person [age=22, name=李四] 2
Person [age=20, name=张三] 1
Person [age=19, name=张三] 3
-----------------------------
1 Person [age=20, name=张三]
2 Person [age=22, name=李四]
3 Person [age=19, name=张三]
4 Person [age=25, name=哇塞]

2.  Comparator---接口(可以理解为比较器,给集合传递比较器集合具有可比性)

  Comparator相当于外部比较器,其作为参数传给具有可比性的集合,使集合具有可比性。比如:      TreeSet ts = new TreeSet(new MyComparator());   比较器需要重写compareTo(Object o1,Object o2)方法,返回值也是下面三个值:

1、返回正整数

2、返回0

3、返回负整数

  可以这么理解:返回1表示当前元素排在与之对比的元素后面,返回-1表示当前元素排在与之对比的元素前面,返回0表示不排序(按其原顺序排列)。(其实并不是1,-1,0;只要是正数负数和0就可以进行区分)

  compareTo(Object o1,Object o2)方法的第一个参数可以理解为基准,而参数上的第二个参数可以理解为与之对比的元素。

1.比如我们想比较人的时候按年龄倒序排列

public class Person{

    private int age;
private String name; public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Person(int age, String name) {
super();
this.age = age;
this.name = name;
} @Override
public String toString() {
return "Person [age=" + age + ", name=" + name + "]";
} }

比较器类:(可以理解为第一个参数是基准,第二个参数是与之对比的元素,返回-1表示基准排在与之对比元素前面,返回1表示基准在与之对比的元素后面)

import java.util.Comparator;

public class PersonComparator implements Comparator<Person> {

    /**
* 第一个参数可以理解为基准,第二个是与之比较的元素 。返回负数表示排在其前面,返回正数表示排在其后面
*/
@Override
public int compare(Person o1, Person o2) {
// 返回负数表示o1排在o2前面
if (o1.getAge() > o2.getAge()) {
return -1;
} // 返回正数表示o1排在o2后面
if (o1.getAge() < o2.getAge()) {
return 1;
}
return 0;
} }

测试代码:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List; public class Test1 {
public static void main(String[] args) {
List<Person> list = new ArrayList<>();
list.add(new Person(20, "张三"));
list.add(new Person(22, "李四"));
list.add(new Person(19, "王五"));
list.add(new Person(19, "张是"));
list.add(new Person(17, "开发"));
list.add(new Person(29, "看")); Collections.sort(list,new PersonComparator());
for(Person p : list){
System.out.println(p);
}
}
}

结果:

Person [age=29, name=看]
Person [age=22, name=李四]
Person [age=20, name=张三]
Person [age=19, name=王五]
Person [age=19, name=张是]
Person [age=17, name=开发]

2.写一个正序的比较器就简单了

(1)直接调用工具类反转比较器实现一个正序比较器:

Comparator<Person> reverseOrder = Collections.reverseOrder(new PersonComparator());

其内部是构造了一个反向比较器:(将基准更换)

    private static class ReverseComparator2<T> implements Comparator<T>,
Serializable
{
private static final long serialVersionUID = 4374092139857L; final Comparator<T> cmp; ReverseComparator2(Comparator<T> cmp) {
assert cmp != null;
this.cmp = cmp;
} public int compare(T t1, T t2) {
return cmp.compare(t2, t1);
}
...
}

(2)修改比较器代码:

import java.util.Comparator;

public class PersonComparator implements Comparator<Person> {

    /**
* 第一个参数可以理解为基准,第二个是与之比较的元素 。返回负数表示排在其前面,返回正数表示排在其后面
*/
@Override
public int compare(Person o1, Person o2) {
// 返回负数表示o1排在o2前面
if (o1.getAge() < o2.getAge()) {
return -1;
} // 返回正数表示o1排在o2后面
if (o1.getAge() > o2.getAge()) {
return 1;
}
return 0;
} }

3.将一个比较器传入TreeSet或者TreeMap是集合有序,或者TreeMap的key值有序(也就是TreeMap排序是将key排序)

  TreeSet中的元素会自动排序,根据传下来的比较器对里面的元素进行排序。TreeMap传入比较器的话是元素作为key才可以排序,如果传入比较器但是key不是比较器指定的元素会报错。。。。。。。

比较器:(正序比较器)

import java.util.Comparator;

public class PersonComparator implements Comparator<Person> {

    /**
* 第一个参数可以理解为基准,第二个是与之比较的元素 。 返回正数表示o1排在o2后面,返回负数表示o1排在o2前面
*/
@Override
public int compare(Person o1, Person o2) {
if (o1.getAge() > o2.getAge()) {
return 1;
} if (o1.getAge() < o2.getAge()) {
return -1;
}
return 0;
} }

测试代码:

package cn.qlq.test;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet; public class TreeSetTest {
public static void main(String[] args) {
Set<Person> list = new TreeSet<>(new PersonComparator());
list.add(new Person(20, "张三"));
list.add(new Person(22, "李四"));
list.add(new Person(19, "王五"));
list.add(new Person(19, "张是"));
list.add(new Person(17, "开发"));
list.add(new Person(29, "看")); for(Person p : list){
System.out.println(p);
}
System.out.println("-----------------------------"); //作为key不会报错,会将key排序
Map map = new TreeMap(new PersonComparator());
map.put(new Person(20, "张三"), "1");
map.put(new Person(22, "李四"), "2");
map.put(new Person(19, "张三"), "3");
map.put(new Person(25, "哇塞"), "4");
for(Object key :map.keySet()){
System.out.println(key+"\t"+map.get(key));
} //作为value报错
Map map2 = new TreeMap(new PersonComparator());
map2.put("1",new Person(20, "张三"));
map2.put("2",new Person(22, "李四"));
map2.put("3",new Person(19, "张三"));
map2.put("4",new Person(25, "哇塞"));
for(Object key :map2.keySet()){
System.out.println(key+"\t"+map2.get(key));
}
}
}

结果:

Person [age=17, name=开发]
Person [age=19, name=王五]
Person [age=20, name=张三]
Person [age=22, name=李四]
Person [age=29, name=看]
-----------------------------
Person [age=19, name=张三] 3
Person [age=20, name=张三] 1
Person [age=22, name=李四] 2
Person [age=25, name=哇塞] 4
-----------------------------
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to cn.qlq.test.Person
at cn.qlq.test.PersonComparator.compare(PersonComparator.java:1)
at java.util.TreeMap.compare(Unknown Source)
at java.util.TreeMap.put(Unknown Source)
at cn.qlq.test.TreeSetTest.main(TreeSetTest.java:37)

补充:Collections.sort的两种用法

  Collections.sort有两种用法,第一个是只传递一个list参数,第二个是传递两个参数(list,Comparator):

    public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
} public static <T> void sort(List<T> list, Comparator<? super T> c) {
Object[] a = list.toArray();
Arrays.sort(a, (Comparator)c);
ListIterator i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set(a[j]);
}
}

(1)Collections.sort(list)默认采用升序排列;  Collections.reverse(list) 是对集合进行反转

package cn.xm.exam.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List; public class Test2 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(5);
list.add(4);
list.add(6);
list.add(3);
list.add(1);
System.out.println(list);
System.out.println("===================");
Collections.sort(list);
System.out.println(list);
}
}

结果:

[5, 4, 6, 3, 1]
===================
[1, 3, 4, 5, 6]

如果想要降序排列可以先正序排列之后再反转即可:

        Collections.sort(list); //正序排列
Collections.reverse(list);//反转集合

(2)Collections.sort(list, Comparator);可以传入一个比较器,也可以将比较器反转

package cn.xm.exam.test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; public class Test2 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(5);
list.add(4);
list.add(6);
list.add(3);
list.add(1);
System.out.println(list);
System.out.println("===================");
Collections.sort(list, new IntegerComparator());
System.out.println(list);
}
} /**
* 一个逆序排列的比较器
*
* @author Administrator
*
*/
class IntegerComparator implements Comparator<Integer> {
@Override
public int compare(Integer o1, Integer o2) {
if (o1 > o2) {
return -1;// 大的排在前面
} else if (o1 < o2) {
return 1;// 小的排在后面
}
return 0;
}
}

结果:

[5, 4, 6, 3, 1]
===================
[6, 5, 4, 3, 1]

当然了,比较器也可以反转之后再次使用,例如:

        List<Integer> list = new ArrayList<>();
list.add(5);
list.add(4);
list.add(6);
list.add(3);
list.add(1);
System.out.println(list); System.out.println("===================");
Comparator<Integer> reverseOrder = Collections.reverseOrder(new IntegerComparator());// 将比较器反转
Collections.sort(list, reverseOrder);// 用反转后的比较器排序 System.out.println(list);

结果:

[5, 4, 6, 3, 1]
===================
[1, 3, 4, 5, 6]

Comparable和Comparator的区别&Collections.sort的两种用法的更多相关文章

  1. java基础——Collections.sort的两种用法

    Collections是一个工具类,sort是其中的静态方法,是用来对List类型进行排序的,它有两种参数形式: public static <T extends Comparable<? ...

  2. Collections.sort的两种用法 转

    /** * @author guwh * @version 创建时间:2011-11-3 上午10:49:36 * 类说明 */ package com.jabberchina.test; impor ...

  3. Collections.sort的两种用法

    http://gwh-08.iteye.com/blog/1233401/ class Foo implements Comparable<Foo>{ @Override public i ...

  4. java基础 -- Collections.sort的两种用法

    /** * @author * @version * 类说明 */ package com.jabberchina.test; import java.util.ArrayList; import j ...

  5. java基础—— Collections.sort的两种用法

    package com.jabberchina.test; import java.util.ArrayList; import java.util.Collections; import java. ...

  6. Collections.sort的三种用法

    /** * @author guwh * @version 创建时间:2011-11-3 上午10:49:36 * 类说明 */ package com.jabberchina.test; impor ...

  7. Java中Collections类的排序sort函数两种用法

    java中的Colletions类主要实现列表List的排序功能.根据函数参数的传递,具体的排序可以分为 : 1.  自然排序(natural ordering). 函数原型:sort(List< ...

  8. Java中Comparable和Comparator接口区别分析

    Java中Comparable和Comparator接口区别分析 来源:码农网 | 时间:2015-03-16 10:25:20 | 阅读数:8902 [导读] 本文要来详细分析一下Java中Comp ...

  9. Comparable与Comparator的区别

    Java的Comparator和Comparable当需要排序的集合或数组不是单纯的数字型时,通常可以使用Comparator或Comparable,以简单的方式实现对象排序或自定义排序. 一.Com ...

随机推荐

  1. Final互评------《弹球学成语》---- 杨老师粉丝群

    一.基于NABCD评论作品,及改进建议 1.根据(不限于)NABCD评论作品的选题;  N(Need,需求):本产品面相青少年及小学生,基于这些用户数量再加上一些休闲玩家,需求量还是比较大的.   A ...

  2. 从两个设计模式到前端MVC-洪宇

    引言 本文将从策略模式和观察者模式两个设计模式讲起,接着过渡到一个经典的复合模式- MVC架构,进而介绍MVC在Web上的适应-Model2架构.之后,我们将视野扩展到前端MVC,看一看前端MVC经典 ...

  3. M1事后总结报告

    设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 解决外卖信息的碎片化和多平台化,通过信息整合的方式来给用户提供一个更优惠更快速方便的外卖平台. 我们的客 ...

  4. 20135327郭皓--Linux内核分析第三周 构造一个简单的Linux系统MenuOS

    Linux内核分析第三周  构造一个简单的Linux系统MenuOS 前提回顾 1.计算机是如何工作的三个法宝 1.存储程序计算机 2.函数调用堆栈 3.中断 2.操作系统的两把宝剑 中断上下文的切换 ...

  5. python数据分析Adult-Salary预测

    具体文档戳下方网站 https://pan.wps.cn/l/s4ojed8 代码如下: import pandas as pdimport numpy as npimport matplotlib. ...

  6. php环境搭建及入门

    在php文件里,写入header('content-type:text/html;charset = uft-8'); <?php header('content-type:text/html; ...

  7. [转帖]Windows 使用netsh 命令行方式处理 windows防火墙的方法

    Windows防火墙命令行手册 https://blog.csdn.net/mystudyblog0507/article/details/79617629 简介 netsh advfirewall ...

  8. [51CTO]区块链在美国:10个案例、10个问题和5个解决方案

    区块链在美国:10个案例.10个问题和5个解决方案 近日,美国国际战略研究中心(CSIS, Center for Strategic and International Studies)发布报告< ...

  9. K8S 使用NFS 创建PV和PVC的例子 学习From https://blog.csdn.net/xts_huangxin/article/details/51494472

    1. 获取资料 网址: https://blog.csdn.net/xts_huangxin/article/details/51494472  感谢原作者 这里面 按照自己的机器情况进行了学习模仿 ...

  10. func_get_args()在php71与php56的区别

    func_get_args() 获取函数的所有参数,返回一个数组 官方:http://www.php.net/manual/en/function.func-get-args.php 但是此函数在ph ...