目录
1 两种接口对应比较方法的参数含义及原理
在继承接口Comparable< E >
实现方法compareTo(E o)
和继承接口Comparator< E >
实现方法compare(E o1, E o2)
中,比较大小时,this(o2)代表当前准备添加进来需要排序的元素,o(o1)代表集合中所有已经排序完成的元素。
- return -1 时,默认新添加的this(o2)大于o(o1),方法默认升序排序,o(o1)在前,this(o2)在后。
- return 1 时,默认新添加的this(o2)小于o(o1),方法默认升序排序,this(o2)在前,o(o1)在后。
- return 0 时,默认this(o2)等于o(o1)
默认都是升序,要降序可以使this(o2) < o(o1)时,return 1;this(o2)>o(o1),return -1。将排序o1(o)在前this(o2)在后,完成降序排序。
总之,只需记住,返回负数,代表 o1(o)排在前; 返回正数,代表 o2(thgis)排在前或
2 compareTo自然排序定制
2.1 用法一:可以直接用于Number对象(基本数据类型的包装类)和String对象
//通过compareTo比较引用类型String类对象的大小
System.out.println("-------------String-------------");
String str1 = "1234y";
System.out.println("sytudf".compareTo("syt"));//3
System.out.println(str1.compareTo("1234y45ttyu"));//-6
//通过compareTo比较基本数据类型的包装类大小
//Byte字节型1字节
//Byte只能用字符串参数装箱,且无法识别整型数据为Byte必须装箱
System.out.println("-------------Byte-------------");
System.out.println(new Byte("12").compareTo(new Byte("124")));//-112
//Short短整型2字节
//Short只能用字符串参数装箱,且无法识别整型数据为Short必须装箱
System.out.println("-------------Short-------------");
System.out.println(new Short("235").compareTo(new Short("345")));//-110
//Integer整型4字节
//Integer可以用值参数装箱,也可以用字符串参数装箱;且值参数自动识别整数数据为int作为参数自动装箱
System.out.println("-------------Integer-------------");
System.out.println(new Integer(45).compareTo(56));//-1
System.out.println(new Integer("3456").compareTo(new Integer("345")));//1
//Long长整型8字节,定义时尾部加L或l
//Long可以用值参数装箱,也可以用字符串参数装箱,用字符串参数时不加L,l;且值参数自动识别整数l数据为Long作为参数自动装箱
System.out.println("-------------Long-------------");
System.out.println(new Long(7845634353543l).compareTo(7856l));//1
System.out.println(new Long("45634").compareTo(34545L));//1;注意:用字符串参数就不用加L
//Float单精度浮点型(小数型)4字节,定义时尾部加f或F
//Float可以用值参数装箱,也可以用字符串参数装箱,用字符串参数时不加F,f;且值参数自动识别小数F,f数据为Float作为参数自动装箱
System.out.println("-------------Float-------------");
System.out.println(new Float(34.67f).compareTo(34.62F));//1
System.out.println(new Float("35.6").compareTo(35.6f));//0
//Double双精度浮点型(小数型)8字节,小数默认是double
//Double可以用值参数装箱,也可以用字符串参数装箱;且值参数自动识别小数数据为Double作为参数自动装箱
System.out.println("-------------Double-------------");
System.out.println(new Double(3456.786).compareTo(3456.756));
System.out.println(new Double("654.345").compareTo(645.345));
//Character字符型,2字节。ASCII码中,1个英文字符占用1个字节,1个汉字字符占用2个字节的空间
//Character可以用值参数装箱,不可以用字符串参数装箱;且值参数自动识别'一个字符'数据为Chacter作为参数自动装箱
System.out.println("-------------Character-------------");
System.out.println(new Character('y').compareTo(new Character('y')));//0
System.out.println(new Character('8').compareTo('9'));//-1
System.out.println(new Character('1').compareTo('A'));//-16
//Boolean布尔型1字节
//Boolean可以用值参数装箱,可以用字符串参数装箱;且值参数自动识别true或false数据为Boolean作为参数自动装箱
System.out.println("-------------Boolean-------------");
System.out.println(new Boolean(false).compareTo(true));//-1
System.out.println(new Boolean("true").compareTo(new Boolean("true")));//0
- Byte和Short只能用字符串参数,不能用值参数。所以比较时无法用值自动装箱,必须用字符串参数手动装箱后使用。
- Character只能用值参数,不能用字符串参数。可以通过值参数在方法参数部分自动装箱
- 其他5种基本数据类型包装类+String类既可以用值参数自动装箱,也可以用字符串参数手动装箱。可以通过值参数在方法参数部分自动装箱
2.2 用法二 : 重写compareTo以定制自定义类的排序规则
- Student类,以属性id决定大小,实现自然排序
- 继承接口Comparable实现方法 public int compareTo(Student o)
public class Student implements Comparable<Student>{
//学生,三个属性,姓名,年龄,学号
private String name;
private int age;
private int id;
public Student( int id,String name, int age){
this.name = name;
this.age = age;
this.id = id;
}
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age = age;
}
public int getId(){
return this.id;
}
//学号不会重复,所以以学号来决定大小
@Override
public int compareTo(Student o) {//o代表当前添加进来需要排序的元素,this代表集合中所有已经排序完成的元素
if(this.id > o.id){
return 1;//默认this大于o,o在前,this在后
}else if(this.id < o.id){
return -1;
}else{
return 0;
}
//return 0;
}
@Override
public String toString() {
//return super.toString();
return getClass().getName()+"[id="+id+",name="+name+",age="+age+"]";
}
}
//Student类继承接口Comparable<E>,实现方法compareTo(E o)
Student stu1 = new Student(2026,"学生1",15);
Student stu2 = new Student(2022,"学生2",23);
Student stu3 = new Student(2020,"学生3",35);
//1.自然排序的自定义类Student
//TreeSet
Set<Student> set1 = new TreeSet<>();
set1.add(stu1);
set1.add(stu2);
set1.add(stu3);
System.out.println(set1);
//TreeMap
Map<Student,Integer> map1 = new TreeMap<>();
map1.put(stu1,23);
map1.put(stu2,24);
map1.put(stu3,45);
System.out.println(map1);
- 运行结果如下
实现自然排序自定义类的TreeSet[com.qx.javaTest.Student[id=2020,name=学生3,age=35], com.qx.javaTest.Student[id=2022,name=学生2,age=23], com.qx.javaTest.Student[id=2026,name=学生1,age=15]]
实现自然排序自定义类的TreeMap{com.qx.javaTest.Student[id=2020,name=学生3,age=35]=45, com.qx.javaTest.Student[id=2022,name=学生2,age=23]=24, com.qx.javaTest.Student[id=2026,name=学生1,age=15]=23}
3 compare比较器排序
3.1 用法一:在对应类中重写compare方法,集合参数new 自定义类对象
- MyData类,以属性data1决定大小,实现比较器
- 继承接口
Comparator<MyData>
,实现方法public int compare(MyData o1, MyData o2)
等于是自己给自己写排序,其他类继承Comparator<MyData>
也可以给MyData写排序方法
Ctrl + I: 实现接口方法
Ctrl + O: 重写父类方法
package com.qx.day10;
import java.util.Comparator;
public class MyData implements Comparator<MyData> {
public MyData(){
}
public MyData(int data1,String name, int data2){
this.data1 = data1;
this.name = name;
this.data2 = data2;
}
private String name;
private int data1;
private int data2;
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void setData1(int data1){
this.data1 = data1;
}
public int getData1(){
return data1;
}
public void setData2(int data2){
this.data2 = data2;
}
public int getData2(){
return data2;
}
@Override
public int compare(MyData o1, MyData o2) {//理解新添加需要排序的元素是o1,已经排好序的元素s为o2
if(o1.data2 > o2.data2){
return 1;//默认,o1>o2,o2在前,o1在后
}else if(o1.data2 < o2.data2){
return -1;默认,o1<o2,o1在前,o2在后
}
else{
return 0;//相等
}
//添加顺序1,3,2,4.
//return 0;//1
//return 1;//1,3,2,4
//return -1;//4,2,3,1
//返回-1,默认o1<o2,o1排在o2之前
}
@Override
public String toString() {
//return super.toString();
return getClass().getName()+"[data1="+data1+",name="+name+",data2="+data2+"]";
}
}
//MyData类继承接口Comparator<E>,实现方法compare(E o1, E o2)
MyData d1 = new MyData(34,"数据1",56);
MyData d2 = new MyData(45,"数据2",6778);
MyData d3 = new MyData(23,"数据3",908);
- 比较器排序的自定义类MyData,比较器类型的自定义类需要在new集合的时候提供该类对象作为参数
Set<MyData> set2 = new TreeSet<>(new MyData());
即可根据自定义方法自动排序
//2.比较器排序的自定义类MyData,比较器类型的自定义类需要在new集合的时候提供该类对象作为参数
//TreeSet
Set<MyData> set2 = new TreeSet<>(new MyData());
set2.add(d1);
set2.add(d2);
set2.add(d3);
System.out.println("实现比较器排序的自定义类的TreeSet"+set2);
//TreeMap
Map<MyData,Student> map2 = new TreeMap<>(new MyData());
map2.put(d1,stu1);
map2.put(d2,stu2);
map2.put(d3,stu3);
System.out.println("实现比较器排序的自定义类的TreeMap"+map2);
- 运行结果
实现比较器排序的自定义类的TreeSet[com.qx.day10.MyData[data1=34,name=数据1,data2=56], com.qx.day10.MyData[data1=23,name=数据3,data2=908], com.qx.day10.MyData[data1=45,name=数据2,data2=6778]]
实现比较器排序的自定义类的TreeMap{com.qx.day10.MyData[data1=34,name=数据1,data2=56]=com.qx.javaTest.Student[id=2026,name=学生1,age=15], com.qx.day10.MyData[data1=23,name=数据3,data2=908]=com.qx.javaTest.Student[id=2020,name=学生3,age=35], com.qx.day10.MyData[data1=45,name=数据2,data2=6778]=com.qx.javaTest.Student[id=2022,name=学生2,age=23]}
3.2 用法二:普通类(即不在类中继承接口重写排序方法),new集合时,提供参数传入匿名类重写比较器,参数为new Comparator<该普通类名>(){重写比较方法compare}
-
- Puppy类
- 普通类,不实现接口
public class Puppy {
private int id;
private String name;
public Puppy(int id,String name){
this.name = name;
this.id = id;
}
public int getId(){
return this.id;
}
public void setId(int id){
this.id = id;
}
public String getNmae(){
return this.name;
}
public void setName(String name){
this.name = name;
}
@Override
public String toString() {
//return super.toString();
return getClass().getName()+"[id="+id+",name="+name+"]";
}
}
//Puppy类,普通类
Puppy p1 = new Puppy(8,"边牧");
Puppy p2 = new Puppy(4,"伯恩山");
Puppy p3 = new Puppy(3,"萨摩耶");
- 普通类Puppy
- 在集合new的时候参数传入匿名类重写比较器。
//普通类Puppy,在集合new的时候传入匿名类实现普通自定义类的定制排序方法
//TreeSet
//自然排序不能这样写,因为本身就是重写在自定义类中直接使用,不需要传参
// Set<Puppy> set3 = new TreeSet<>(new Comparable<Puppy>(){
// @Override
// public int compareTo(Puppy o) {
// //return 0;
//
// }
// });
Set<Puppy> set3 = new TreeSet<Puppy>(new Comparator<Puppy>(){
@Override
public int compare(Puppy o1, Puppy o2) {
//return 0;
if(o1.getId() > o2.getId()){
return 1;
}else if(o1.getId() < o2.getId()){
return -1;
}else{
return 0;
}
}
});
set3.add(p1);
set3.add(p2);
set3.add(p3);
System.out.println("普通自定义类在new TreeMap时传匿名对象重写比较器"+set3);
//TreeMap,key和value都是自定义类的情况,
Map<Puppy,MyData> map3 = new TreeMap<>(new Comparator<Puppy>(){
@Override
public int compare(Puppy o1, Puppy o2) {
//return 0;
if(o1.getId() > o2.getId()){
return -1;
}else if(o1.getId() < o2.getId()){
return 1;
}else{
return 0;
}
}
});
map3.put(p1,d1);
map3.put(p2,d2);
map3.put(p3,d3);
System.out.println("普通自定义类在new TreeMap时传匿名对象重写比较器"+map3);
普通自定义类在new TreeMap时传匿名对象重写比较器[com.qx.javaTest.Puppy[id=3,name=萨摩耶], com.qx.javaTest.Puppy[id=4,name=伯恩山], com.qx.javaTest.Puppy[id=8,name=边牧]]
普通自定义类在new TreeMap时传匿名对象重写比较器{com.qx.javaTest.Puppy[id=8,name=边牧]=com.qx.day10.MyData[data1=34,name=数据1,data2=56], com.qx.javaTest.Puppy[id=4,name=伯恩山]=com.qx.day10.MyData[data1=45,name=数据2,data2=6778], com.qx.javaTest.Puppy[id=3,name=萨摩耶]=com.qx.day10.MyData[data1=23,name=数据3,data2=908]}
4 自然排序和比较器排序的区别总结
- 自然排序本身可以用作基本数据类型的包装类(如Character,);比较器不可以
- 重写比较器的类,new集合的时候需要参数提供对象,该对象包含此类的比较器(可以类自己重写比如MyData,也可以在new集合时提供参数比如Puppy);重写自然排序的类集合不用
- 比较器参数o1表示集合中已经排序完成的所有元素,o2表示当前新添加的一个;自然排序参数o表示集合中已经排序完成的所有元素,对象自身this表示当前新添加的一个
5 自由改写理解定制排序返回值含义
- 假设方法始终只return 1 ,表示的含义则为新添加的this(o2)始终更大,排在后。集合为按照元素的添加顺序存储
- 假设方法只 return 0,表示所有添加进来的元素都相同,则只有集合为空时能存储一个元素。因为TreeSet和TreeMap的key都不可重复
- 假设方法只 return -1 ,表示的含义则为新添加的this(o2)始终更小,排在前。集合为按照元素的添加顺序的逆序存储