您的位置:首页 > 其它

equals方法和hashcode方法的区别

2018-03-15 01:11 495 查看
最近在准备面试的时候,了解到这一块,然后今晚上就查找资料,然后自己实际写代码,理解了其中的真实区别,在此记录下来,方便自己以后的复习,一个宗旨,学习不仅仅是为了面试,而是提升自己的一个漫长过程。废话不多说,就把自己觉得重点的理解写下来。
equals方法和hashcode方法都是object类中的一个方法,每个object类中都会有equals方法,在没有被重写的情况下,equals方法和“==”的作用是一样的,都是判断两个对象在内存空间的引用地址是否一样。hashcode方法也可以用来鉴定两个对象是否一样,区别是它返回的是int类型的值,这个int值是内存地址转换而来,所以如果没有重写hashcode方法之前,任何对象的hashcode返回值都是不一样的。但是平常在比较的时候一般不会用hashcode来判断,因为它返回的是int,不是太直观,它基本会出现在集合类中比如map和set,接下来会说明。
在谈到重写之前,有下边一段总结,感觉蛮不错:
哈希码产生的依据:哈希码并不是完全唯一的,它是一种算法,让同一个类的对象按照自己不同的特征尽量的有不同的哈希码,但不表示不同的对象哈希码完全不同。也有相同的情况,看程序员如何写哈希码的算法。

1.equal()相等的两个对象他们的hashCode()肯定相等,也就是用equal()对比是绝对可靠的。

2.hashCode()相等的两个对象他们的equal()不一定相等,也就是hashCode()不是绝对可靠的。
因此有以下的几句话:对于需要大量并且快速的对比的话如果都用equal()去做显然效率太低,所以解决方式是,每当需要对比的时候,首先用hashCode()去对比,如果hashCode()不一样,则表示这两个对象肯定不相等(也就是不必再用equal()去再对比了),如果hashCode()相同,此时再对比他们的equal(),如果equal()也相同,则表示这两个对象是真的相同了,这样既能大大提高了效率也保证了对比的绝对正确性
看一下map的put方法源码:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//是否覆盖
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}

modCount++;
addEntry(hash, key, value, i);//插入操作
return null;
}在hashmap中,由于key是不可以重复的,它在判断key是否重复时就判断了hashCode()方法,而且也用到了equals()方法。此处“不可以重复”指的是equals()和hashCode()只要有一个不等就可以了。
看一下测试代码:自己重写了equals方法和hashcode方法,挨着注释,进行结果输出,可以最终得到结论是只有两个方法都被重写,两个对象才是真正的一样。
package hashcode;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

public class Student {

private String name;
private int age;

public Student(String name,int age){
this.name=name;
this.age = age;
}
public void setAge(int age){
this.age = age;
}

@Override
public boolean equals(Object obj) {
Student s = (Student) obj;
if(this.name.equals(s.name)){
return true;
}else{
return false;
}
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode()); //避免单独相加的偶合性
System.out.println("hashcode:"+result);
return result;
}

public static void main(String[] args) {
LinkedList<Student> list = new LinkedList<Student>();
Set<Student> set = new HashSet<Student>();
Student s1 = new Student("yhl",1);
Student s2 = new Student("yhl",1);
System.out.println("s1==s2:"+(s1==s2));
System.out.println("s1.equal(s2):"+(s1.equals(s2)));
list.add(s1);
list.add(s2);
System.out.println("list的长度:"+list.size());
set.add(s1);
set.add(s2);
s2.setAge(12);
boolean remove = set.remove(s2);
System.out.println("remove:"+remove);
System.out.println("set的长度:"+set.size());
String aa = new String("11");
String bb = new String("11");
System.out.println(aa.equals(bb));//String的equals方法已经重写
}
}
说明:当我们将某个对象存到set中时,如果该对象的属性参与了hashcode的计算,那么以后就不能修改该对象参与hashcode计算的那些属性了,否则会引起意向不到的错误。就比如上边,在remove之前修改了age,则对象的hashcode返回值就跟之前不一样,所以remove是false。
运行结果:



最后,一定要注意, 在重写equals方法的时候,一定要重写hashCode方法,有这个要求的原因在于,要考虑到hashcode值在类似HashMap、HashTable、HashSet的这种散列的数据类型中的运用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: