Java进行对象比较时的equals()和hashcode()方法
Posted akyna-zh
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java进行对象比较时的equals()和hashcode()方法相关的知识,希望对你有一定的参考价值。
Java进行对象比较中的equals()和hashcode()
1.equals()方法与"=="的比较与分析
首先提出一个误区:
- == 比较时进行地址的比较
- equals 比较时进行值的比较
String a = "123";
String b = "123";
System.out.println(a.equals(b)); // true
System.out.println(a == b); // true
String a1 = new String("123");
String b1 = new String("123");
System.out.println(a1.equals(b1)); // true
System.out.println(a1 == b1); // false
好像没问题。
然而阅读源码Object类,我发现对象中默认equals方法进行的是地址的比较
public boolean equals(Object obj) {
return (this == obj);
}
再阅读源码String类,可以发现String类中重写了equals方法,覆盖掉了Object的equals方法,所以String的equals是值比较!
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
所以equals()不一定进行值的比较,在使用自己创建的类时,若想进行值的比较就必须重写equals()方法。
2.应该如何重写equals方法
- (1)重写equals方法的目的:
重写equals是 在两个对象某些字段相等时就认定两个对象相等 的情况下进行的
- (2)重写一个完美的equals()的步骤:
1.显式参数命名为otherObject,稍后将它强制转换为另一个名为other的变量
2.检测this与otherObject是否相等
3.检测otherObject是否为null
4.比较this与otherObject的类,如果equals的语义可以在子类中改变,就使用getclass检测
如果所有的子类都有相同的相等性语义,就使用instanceof检测
5.将otherObject强制转换为相应类类型的变量
6.使用 == 比较基本类型字段 使用 Object.equals比较对象字段
by 《core Java》
注:
instanceof进行类型检查规则是:你属于该类or该类的派生类;
getClass获得类型信息采用==来进行检查是否相等的操作是严格的判断,只会判断”本类”.
example:
当两个人年龄相同时,我们认为这两个对象相同:
class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age;
}
@Override
public int hashCode() {
return Objects.hash(age);
}
}
test:
Person p1 = new Person(15, "Mary");
Person p2 = new Person(15, "Mark");
System.out.println(p1.equals(p2)); // true
System.out.println(p1 == p2); // false
3.为什么重写equals()时要重写hashcode()
可以看到上述程序中不但重写了equals()方法,同时重写了hashcode()方法:
@Override
public int hashCode() {
return Objects.hash(age);
}
重写equals最好要重写hashcode(),对需要进行比较的部分字段进行hash(),也就是让值通过一个哈希函数获取到对应的哈希值
为何?
其实这样是为了提高程序的效率:
如果不重写hashcode()的话,可以试想一下,向一个元素个数为10000的集合中插入一个新的元素,就需要对之前的10000个元素进行比较,每次比较都要调用一次equals()比较每一个需要比较的字段,可以容易地想象出比较需要花费的时间复杂度是巨大的。
如果插入元素时,先通过hashcode的寻找可以飞速地判断集合中是否存在一样的元素,在O(1)的时间内可以解决集合插入问题。
同时重写hashcode()也保证了对象进行equals时,如果为true,其对应的hashcode也一定相等。虽然在不涉及集合操作时不重写hashcode()不影响比较,编译运行也不会报错,但是这会违反Java中对象的比较规则。
关于这两个方法的重要规范:
规范1:若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值。说得简单点就是:“如果两个对象相同,那么他们的hashcode应该相等”。不过请注意:这个只是规范,如果你非要写一个类让equals(Object obj)返回true而hashcode()返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了Java规范,程序也就埋下了BUG。
规范2:如果equals(Object obj)返回false,即两个对象“不相同”,并不要求对这两个对象调用hashcode()方法得到两个不相同的数。说的简单点就是:“如果两个对象不相同,他们的hashcode可能相同”。
over
以上是关于Java进行对象比较时的equals()和hashcode()方法的主要内容,如果未能解决你的问题,请参考以下文章