hashcode与equals的区别
hashcode与equals的区别
一、hashCode()和equals()是什么?
hashCode()方法和equals()方法的作用其实一样,在Java里都是用来对比两个对象是否相等一致。
二、Object默认的hashcode()和equals()
equals:
默认比较的为对象的地址
public boolean equals(Object obj) {
return (this == obj);
}
hashcode:
使用对象的内存地址编号
public native int hashCode();
三、Integer和String的equals()和hashcode()
1、String
equals:
对Object进行实现,比较的是每个字符
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;
}
hashcode:
对Object进行实现,计算的是每个字符对应的ASCII码+ 31乘以上一个的ASCII码
public int hashCode() {
//hash默认为0
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
2、Integer
equals:
直接比较的该数字
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
public int intValue() {
return value;
}
hashcode:
也是返回的该数值
public int hashCode() {
return Integer.hashCode(value);
}
public static int hashCode(int value) {
return value;
}
3、测试
注意:满足下列条件的,必须要实现hashcode和equals方法
①equals比较值相等的,hashcode一定相等
我们可以直接使用Integer和String的equals来比较,因为已经默认帮我们实现了其父类的hashcode和equals方法
String a="abb";
String b="abb";
//true
System.out.println(a.equals(b));
//96353
System.out.println(a.hashCode());
//96353
System.out.println(b.hashCode());
Integer c=162;
Integer d=162;
//162
System.out.println(c.hashCode());
//162
System.out.println(d.hashCode());
//true
System.out.println(c.equals(d));
注意:所有的包装类对象之间值的比较,全部使用equals方法比较。
说明:对于Integer var=?在-128至127之间的赋值,Integer对象是在IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用equals方法进行判断。
Integer a = 235;
Integer b = 235;
if (a.equals(b)) {
// code
}
②hashcode相等的,其值不一定相等
从重写hashcode的规则可以得出
String a1="a";
Integer b1=97;
//true
System.out.println(a1.hashCode()==b1.hashCode());
三、从对象中进一步得出hashcode和equals的区别
1、未重写hashcode与equals:
public class Student {
private String name;
private Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
//getter setter tostring
}
Student s1 = new Student("张三", 11);
Student s2 = new Student("张三", 11);
// false
System.out.println(s1.equals(s2));
// 1956725890
System.out.println(s1.hashCode());
// 356573597
System.out.println(s2.hashCode());
我们发现默认使用的equals和hashcode的方法为Object中的方法,equals比较的是对象的地址。hashcode计算的是默认的地址编号。所以我们必须要重新hashcode和equals方法。
2、重新hashcode与equals:
public class Student {
private String name;
private Integer age;
public Student() {
}
public Student(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Student student = (Student) o;
if (!Objects.equals(name, student.name)) {
return false;
}
return Objects.equals(age, student.age);
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (age != null ? age.hashCode() : 0);
return result;
}
//getter setter tostring
}
Student s1 = new Student("张三", 11);
Student s2 = new Student("张三", 11);
// true
System.out.println(s1.equals(s2));
// 24021570
System.out.println(s1.hashCode());
// 24021570
System.out.println(s2.hashCode());
这次我们发现,使用equals判断相等,hashcode也一致
equals判断的是不是同一对象,若为同一对象,那么我们直接比较其对象的值,若都相等返回true,否则返回false
hashcode计算的是每一个属性值计算成的hashcode值进行的累加操作。
3、结论
从Integer和String类和Student类综合得出:
①equals()相等的两个对象他们的hashCode()肯定相等,也就是用equals()对比是绝对可靠的。
②hashCode()相等的两个对象他们的equals()不一定相等,也就是hashCode()不是绝对可靠的。
四、hashCode()和equals()在集合中的使用
1、对于需要大量并且快速的对比的话如果都用equals()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equals()去再对比了),如果hashCode()相同,此时再对比他们的equals(),如果equals()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性!
2、这种大量的并且快速的对象对比一般使用的hash容器中,比如HashSet,HashMap,HashTable等等,比如HashSet里要求对象不能重复,则他内部必然要对添加进去的每个对象进行对比,而他的对比规则就是像上面说的那样,先hashCode(),如果hashCode()相同,再用equals()验证,如果hashCode()都不同,则肯定不同,这样对比的效率就很高了。
例如,我们通过HashSet来存储对象,其默认的形式是无序,且唯一。所以HashSet来做去重判断的时候,首先会去比较hashcode,若hashcode不等,则不添加此值。否则hashcode相等再去比较equals,若相等,则添加此值,否则,不添加此值
HashSet<Student> hashSet=new HashSet<>();
hashSet.add(new Student("zs", 11));
hashSet.add(new Student("zs", 11));
Iterator<Student> iterator = hashSet.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
未重写hashcode与equals的Student类:
Student{name='zs', age=11}
Student{name='zs', age=11}
我们发现没有去重。
重写hashcode与equals的Student类:
Student{name='zs', age=11}
我们发现已经去重