Java中对象的比较有三种方式
一:实现Compareable接口,重写compareTo方法(对类的侵入性太强)
class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
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 String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
return this.age-o.age;
}
}
测试结果
public static void main(String[] args) {
Student[] students = new Student[2];
students[0] = new Student("shuo",23);
students[1] = new Student("zhuo",13);
Arrays.sort(students);
// [Student@14ae5a5, Student@7f31245a]
// 重写toString方法之后
// [Student{name='zhuo', age=13}, Student{name='shuo', age=23}]
System.out.println(Arrays.toString(students));
}
二:使用Comparator,重写compare方法
// 按照年龄比较
class AgeComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
}
// 按照姓名比较
class NameComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
// o1 是一个字符串 它自己有compareTo方法
return o1.getName().compareTo(o2.getName());
}
}
三:equals方法
- 基本类型与基本类型封装型进行“==”运算符的比较,基本型封装型将会自动拆箱变为基本型后再进行比较,因此Integer(0)会自动拆箱为int类型再进行比较,返回true
- 两个Integer类型进行“==”比较,如果其值在-128至127,那么返回true,否则返回false。这跟Integer.valueOf()的缓冲对象。
- 两个基本类型的封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true
- 基本型封装类型调用equals(),但是参数是基本类型,这时候,会先进行自动装箱,基本型转换为其封装类型,在进行3中的比较。
int i = 189;
char d = 28;
Integer c = 189;
Integer j = new Integer(189);
System.out.println(i==j);//true
System.out.println(c==j);//false
System.out.println(j.equals(i));//true
System.out.println(c.equals(d));//false
使用equals,重写eauals方法
没有重写equals时,是直接用==判断的,而String中重写了equals方法。
public class TestWork {
public String name = "abc";
public static void main(String[] args) {
TestWork test = new TestWork();
TestWork testB = new TestWork();
System.out.println(test.equals(testB)+","+test.name.equals(testB.name));
// false,true
}
}
@Override
public boolean equals(Object o) {
// 是不是两个引用指向同一个对象
if (this == o) return true;
// 如果传进来是一个null
if (o == null) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
总结:三种比较方法的对比
重写的方法 | 说明 |
---|---|
Compare接口的compareTo方法 | 需要手动实现接口,侵入性比较强,每次用该类都有顺序,属于内部顺序;Compareable接口将毕节哦代码嵌入自身类中;Comparable的比较方法compareTo只有一个参数; |
Comparator接口的compare方法 | 需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性强;Comparator在一个独立的类中实现比较。Comparator接口的比较方法compare有两个参数; |
重写Object的方法equals | 因为所有类都是继承自Object的,所以直接重写即可,不过只能比较相等与否 |
集合框架中PriorityQueue的比较方式
Alt+7 查看PriorityQueue的源码
offer方法的实现方式
如果是第一个元素,直接将插入的元素放到0下标,不存在比较。
不是第一个元素,发生向上调整。
siftUp方法的实现方式
向上调整使用了两个方案
- 用Compareator
- 用Comparable(默认)
compare的第一个参数是插入的元素 x 是要插入的元素
不带参数的PriorityQueue方法
public static void main(String[] args) {
// 将比较器作为构造函数的参数传入
// 可以控制 o1-o2 来控制大小堆
PriorityQueue<Student> queue = new PriorityQueue<>(new AgeComparator());
queue.offer(new Student("shuo",23));
queue.offer(new Student("zhuo",13));
// [Student{name='zhuo', age=13}, Student{name='shuo', age=23}]
System.out.println(queue);
}