文章目录
前言
本人是一个刚刚上路的IT新兵,菜鸟!分享一点自己的见解,如果有错误的地方欢迎各位大佬莅临指导,如果这篇文章可以帮助到你,劳请大家点赞转发支持一下!
上一篇文章,讲解了优先级队列,从这里开始就对插入的数据有要求了,那就是插入的数据必须可以比较,有优先级之分。并且以后要用到比较的地方也越来越多,所以今天就来讲一讲java对象的比较
一、PriorityQueue中插入对象
优先级队列在插入元素时有个要求:插入的元素不能是null或者元素之间必须要能够进行比较,那么我们要如何让插入的对象实现比较功能呢?
class Student {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Compare {
public static void main(String[] args) {
Student stu1 = new Student("小明",15);
Student stu2 = new Student("小红",16);
PriorityQueue<Student> priorityQueue = new PriorityQueue<>();
priorityQueue.offer(stu1);
priorityQueue.offer(stu2);
}
}
运行上述代码时,会抛出运行时异常。
优先级队列底层使用堆,而向堆中插入元素时,为了满足堆的性质,必须要进行元素的比较,而此时Student是没有办法直接进行比较的,因此抛出异常。
二、数据的比较
1.基本类型的比较
在Java中,基本类型的对象可以直接比较大小。
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println(a > b);
System.out.println(a < b);
System.out.println(a == b);
char c1 = 'A';
char c2 = 'B';
System.out.println(c1 > c2);
System.out.println(c1 < c2);
System.out.println(c1 == c2);
boolean b1 = true;
boolean b2 = false;
System.out.println(b1 == b2);
System.out.println(b1 != b2);
}
2.自定义类的比较
class Student {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Student student1 = new Student("小明",15);
Student student2 = new Student("小红",15);
Student student3 = student1;
//System.out.println(student1 > student2);
//编译报错
System.out.println(student1 == student2);
//编译成功,打印false,因为student1和student2指向的是不同对象
System.out.println(student1 == student3);
//编译成功,打印true,因为student1和student2指向的是同一个对象
}
- Java中引用类型的变量不能直接按照 > 或者 < 方式进行比较。
那为什么 == 可以比较呢?
对于用户实现自定义类型,都默认继承自Object类,而Object类中提供了equal方法,而==默认情况下调用的就是equal方法,但是该方法的比较规则是:没有比较引用变量引用对象的内容,而是直接比较引用变量的地
址。
Object中equal的实现,是直接比较的是两个引用变量是否指向同一个地址
3.对象的比较
1.覆写基类的equals
class Student {
public String name;
public int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
//如果是同一个对象,返回true
if (o == null || getClass() != o.getClass()) return false;
//如果为空或不是同一类型,返回false
Student student = (Student) o;
//强转后,比较,这里认为只要姓名年龄相同就是一个人
return age == student.age && Objects.equals(name, student.name);
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
Student student1 = new Student("小明",15);
Student student2 = new Student("小红",15);
System.out.println(student1 == student2);//重写了equals,返回true
}
}
覆写基类equal的方式虽然可以比较,但缺陷是:equal只能按照相等进行比较,不能按照大于、小于的方式进行比较。
2.基于Comparble接口类的比较
Comparble是JDK提供的泛型的比较接口类,源码如下:
compareTo返回一个值
这个值 < 0: 表示 this 指向的对象小于 o 指向的对象
这个值 == 0: 表示 this 指向的对象等于 o 指向的对象
这个值 > 0: 表示 this 指向的对象大于 o 指向的对象
对用用户自定义类型,如果要想按照大小与方式进行比较时:在定义类时,实现Comparble接口即可,然后在类中重写compareTo方法。
class Student implements Comparable<Student>{
public String name;
public int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student o) {
//默认null最小
if(o == null) {
return 1;
}
//自己定义如何比较大小
//return this.age - o.age;//凭年龄比较大小
return this.name.compareTo(o.name);//凭姓名比较大小
//String类自身就重写了compareTo方法,会优先调用自己的
}
public static void main(String[] args) {
Student student1 = new Student("小明",15);
Student student2 = new Student("小红",15);
System.out.println(student1.compareTo(student2));
// == 0,表示是一个同学
// < 0,表示 student1 比较小
// > 0,表示 student1 比较大
}
}
Compareble是java.lang中的接口类,可以直接使用。
用这种写法呢,就将比较方式写死了,就不能再通过其他属性来比较了,侵略性强。
3.基于比较器比较
class Student {
public String name;
public int age;
}
//基于姓名的比较器
class NameComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
//基于年龄的比较器
class AgeComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
}
可以看到两个比较器都实现了Comparator接口,并重写了compare方法。
- 划重点,所以写比较器要实现Comparator接口,并重写compare方法!
public static void main(String[] args) {
Student student1 = new Student("小明",15);
Student student2 = new Student("小红",15);
//创建比较器对象
AgeComparator ageComparator = new AgeComparator();
NameComparator nameComparator = new NameComparator();
int flg1 = ageComparator.compare(student1,student2);
System.out.println(flg1);
int flg2 = nameComparator.compare(student1,student2);
System.out.println(flg2);
// == 0,表示是一个同学
// < 0,表示 p 比较小
// > 0,表示 q 比较大
}
虽然比较器,可以让你灵活的切换比较属性,但是切换比较属性也是需要改写代码的,所以比较器比较对代码的侵略性强
三种比较方式的特点
比较方式 | 特点 |
---|---|
覆写equals方法 | 因为所有类都是继承自 Object 的,所以直接覆写即可,不过只能比较相等与否 |
需比较的类实现了Comparable接口,并重写了compareTo方法 | 需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于内部顺序 |
创建比较器类,通过比较器对象进行比较(比较器类要实现Comparator接口并重写compare方法) | 需要实现一个比较器对象,对待比较类的侵入性弱,但对算法代码实现侵入性强 |
总结
例如:以上就是今天要讲的内容,本文分享了java中自定义类的三种比较方法,如果文章中有谬误,欢迎大家批评指正。
路漫漫,不止修身也养性。