equals方法和hashcode方法的区别

最近在准备面试的时候,了解到这一块,然后今晚上就查找资料,然后自己实际写代码,理解了其中的真实区别,在此记录下来,方便自己以后的复习,一个宗旨,学习不仅仅是为了面试,而是提升自己的一个漫长过程。废话不多说,就把自己觉得重点的理解写下来。

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的这种散列的数据类型中的运用










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值