目录
引入-如果在优先级队列中放入自定义类对象有什么要求?
- 优先级队列要求:插入的元素不能是null或者元素之间必须能够比较。
- 如果在优先级队列中插入自定义对象,必须是可以比较的对象。为什么?因为优先级队列底层是用堆实现的,向堆中插入元素,必然是需要上下调整的,如果插入的元素无法比较。会抛出异常。
基本类型的比较(Int,char,boolean等)
- Java中的基本类型可以直接比较大小。如下
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
public class Compare {
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 flg1=true;
boolean flg2=false;
System.out.println(flg1==flg2);
System.out.println(flg1!=flg2);
}
}
对象类型的比较
- 对象类型不能用> < 等比较,但是可以用==比较。
- 因为自定义类型默认是继承自Object类,而Object类中提供了equals方法,==默认情况下就是调用equals方法。这个方法会比较两个对象的地址来判断是否是同一个对象,不会比较内容。
- 如果想要比较两个对象的内容是否相等,就必须重写equlas方法。
下面对比着看
1.==和equals()方法
- ==比较两个对象时,比较的是对象在内存中的地址是否一致,也就是比较两个对象是否为同一个对象。
- equals()方法可以依据对象的值来判定是否相等。
- equals方法是Object类中的默认方法,查看Object中equals()的默认实现:
public boolean equals(Object obj){
return(this == obj);
}
- 从默认实现中可以看出,没有重写过的equals方法和==是一样的。都是比较两个对象的内存地址。
- 为什么用equals方法直接比较两个字符串对象可以判断是否相等?因为Java中的String类中重写了equals方法。源代码如下:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
- 不仅String类,Java中很多类自身都重写了equals()方法。
重写equals方法使用举例:
public class Student {
private String name;
private int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
//重写equals方法。便于比较
@Override
public boolean equals(Object obj){
return true;//我们这样写,就是不管三七二十一,全给返回true
}
public static void main(String[] args) {
Student sn=new Student("zhagnsan",20);
Student sz=new Student("lisi",18);
System.out.println(sn.equals(sz)); //true
System.out.println(sn.equals(" "));//true 无论和什么对象比较都返回true.
}
}
2.hashCode()方法和equals()方法
- hashCode()方法是Object类中默认的方法。
- hashCode()方法的作用是服务于建立在散列表上的类,比如Java集合中的HashMap,HashSet等。hashCode()方法获取对象中的哈希值,通过哈希值来确定对象在哈希表中的索引位置(哈希值本身是一个
int
型的整数)
举例:
public static void main(String[] args) {
Student s1=new Student("ss",18);
Student s2=new Student("zz",19);
HashSet<Student> stuSet=new HashSet<>();
stuSet.add(s1);
stuSet.add(s2);
System.out.println(s1.equals(s2));
System.out.println(s1);
System.out.println(s2);
System.out.println(stuSet);
}
true
Student@1b6d3586
Student@4554617c
[Student@4554617c, Student@1b6d3586]
Process finished with exit code 0
- HashSet集合不会存储重复的对象。按理来说,s1和s2应该是相等的。不应该被重复放进stuSet中,但是结果显示,出现了重复的对象,因为s1和s2的哈希值不同,所以就会被存在HashSet的不同位置。
- 将对象存储在HashSet时,会先根据对象的哈希值找到相应的索引位置看是否有对象。如果没有就会直接插入,如果有,就会用equals方法来判断位置上的对象与待插入对象是否为相同对象。相同就用新值刷新旧值。不相等就将待插入对象挂在已存在对象的后面。
3.Comparator接口和Comparable接口
- 重写equals方法可以判断自定义类的对象是否相等,但是无法判断大小。Java中提供了两个接口来实现对象大小的比较。一个是Comparator,一个是Comparable。
Comparable接口
- 自定类型如果实现了Comparable接口,就表示该类的对象可以进行比较。
- 实现Comparable接口需要重写其中的compareTo方法。
- Comparable接口具体实现如下:
public interface Comparable<E>{
// 返回值:
// <0 表示当前对象小于O表示的那个对象
// ==0 表示当前对象和要比较的对象相等
// >0 表示当前对象大于要比较的对象对象
int compareTo(E o);
}
具体使用:
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
@Override
public int compareTo(Student o){
return this.age<o.age ? -1:(this.age==o.age?0:1);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public static void main(String[] args) {
Student s1=new Student("ss",18);
Student s2=new Student("zz",19);
Student s3=new Student("kk",21);
TreeSet<Student> stuSet=new TreeSet<>();
stuSet.add(s1);
stuSet.add(s2);
stuSet.add(s3);
stuSet.forEach(a-> System.out.println(a));
}
}
- 重写了ComparaTo方法后,student对象进行比较时,就会按照age的大小进行比较。我们要做的,只是在ComparaTo方法中明确比较的规则。
Comparator接口
- 实现Comparator接口需要重写其中的compare方法。
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "name:"+name + " age:"+age;
}
public static void main(String[] args) {
Student stu1 = new Student("sakuraamy",20);
Student stu2 = new Student("sakurabob",21);
Student stu3 = new Student("sakura",19);
ArrayList<Student> stuList = new ArrayList<>();
stuList.add(stu1);
stuList.add(stu2);
stuList.add(stu3);
//直接用内部类的的方式实现Comparator接口
Collections.sort(stuList, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
return (o1.age<o2.age ? -1 : (o1.age == o2.age ? 0 : 1));
//return o1.name.compareTo(o2.name);
}
});
System.out.println(stuList);
}
}
- 由此可见,实现Comparator接口比实现Comparable接口更简单和灵活。
总结
很多场景需要明确要求两个对象是可以比较的。关于Java中两个对象的比较规则如下:
- 如果是两个基本类型,可以直接进行> < 和==比较
- 如果是两个引用类型,不可以直接进行> < 比较,但是可以进行==比较。(默认调用Object中的equals方法)
- 对于自定义类型,默认是比较地址,比较两个对象是否是同一个对象,如果想要比较内容,需要重写equals方法。
- 对于自定义类型,若想依据某种规则来比较大小,可以实现Comparable接口或者Comparator接口,前者需要重写compareTo方法,后者需要重写compare方法。后者更灵活一些。
自定义类型也是引用类型,只不过是除了Java本身提供的String这种之外的,你自己定义的,比如Student类