曾经去一家公司面试,上来第一道问题就是问这个,原题目大概是:给你一个Student类 实现Comparable接口,如何写这个compareTo方法。
当时很蒙,因为长时间的CURD,只是用的比较多,但是基础相对薄弱,结果必然是铩羽而归。
为什么你经验很多了还会问这样的问题?
因为经验越是多,越应该不只停留在表面上,底层以及基础知识必须扎实,这简直是铁律。
不多说了,把排序比较器总结如下:
Java的排序一般是2种,Comparable与Comparator。
1、Comparable
import java.util.Comparator;
import java.util.Objects;
import java.util.TreeSet;
/**
* Comparable演示
*/
public class Student implements Comparable<Student> {
private String name;
private Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public boolean equals(Object o) {
// 如果两个对象的引用地址相等,则返回true。
if (this == o) return true;
// 如果被比较的元素为空或者被比较的对象类型与当前类类型不一致则返回false.
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
// 如果不是同一个对象,但是类不为空且是同一类型,则比较名字和年龄是否相同
return Objects.equals(name, student.name) && Objects.equals(age, student.age);
}
@Override
public int compareTo(Student o) {
// 如果年龄相同,则再比较名字
int a = this.age - o.getAge();
// 如果年龄相同,则对比名字,如果名字compareTo相同则返回0
int r = (a == 0 ? this.name.compareTo(o.getName()) : a);
return r;
}
public static void main(String[] args) {
// 构建TreeSet实例时,使用了无参构造函数,则使用的排序是自然排序。
// TreeSet中的对象必须实现Comparable接口,重写compareTo()方法。
Student s1 = new Student("xiaobu", 12);
Student s2 = new Student("pang", 12);
TreeSet<Student> treeSet = new TreeSet<>();
treeSet.add(s2);
treeSet.add(s1);
System.out.println(JSON.toJSON(treeSet));
}
}
小结:Comparable的使用场景是被某个类实现。那么凡是这个类的对象都具有了比较的功能。(毕竟对象类型与基础数据类型不同,天生没有自己的比较规则,需要后天给它实现)
实现Comparable接口,必须要重写Comparable的compareTo()方法与当前对象的hashCode()和equals()方法。
缺点:如果实体类比较多,则产生大量的额外工作量。
2、Comparator
import java.util.Comparator;
/**
* Student使用比较器Comparator
*/
public class Student {
private String name;
private int age;
public Student(String name, int age){
this.name = name;
this.age = age;
}
// getter setter ....
public static void main(String[] args) {
TreeSet<Student> students = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 如果年龄相同,则再比较名字
int a = o1.age - o2.getAge();
// 如果年龄相同,则对比名字,如果名字compareTo相同则返回0
int r = (a == 0 ? o1.name.compareTo(o2.getName()) : a);
return r;
}
});
}
}
小结:Comparator的使用场景是临时的,不需要提前定义一个比较器,也跟具体的类没有关系。即用时才实现一下比较规则。
优点:用到比较器的类比较是少数,如果用Comparable,那么有100个实体类 这100个实体类都要实现Comparable且重写compareTo()方法与当前对象的hashCode()和equals()方法。费时费力。
而Comparator则不需要这样。谁用到比较器谁自己临时写一个就可以。
没有绝对的好与坏,根据实际需要来决定即可。