关于hashcode与equals

关于hashcode与equals

1.什么是hashcode,意义何在?

object类中提供了方法 public native int hashCode();

从Object角度看,JVM每new一个Object,它都会将这个Object丢到一个Hash表中去,这样的话,下次做Object的比较或者取这个对象的时候(读取过程),它会根据对象的HashCode再从Hash表中取这个对象。这样做的目的是提高取对象的效率。若HashCode相同再去调用equal。

从集合角度,equals方法可用于保证元素不重复,但如果每增加一个元素就检查一次,若集合中现在已经有1000个元素,那么第1001个元素加入集合时,就要调用1000次equals方法。如果equals方法是比较复杂的判断,这显然会大大降低效率。 于是,Java采用了哈希表的原理。

哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。

这样一来,当集合要添加新的元素时,先调用这个元素的HashCode方法,就一下子能定位到它应该放置的物理位置上。

(1)如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;

(2)如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了;

 

(3)不相同的话,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同HashCode的对象放到这个单链表上去,串在一起(很少出现)。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。 

 

2.为什么重写Object的equals(Object obj)方法尽量要重写Object的hashCode()方法

  首先我们需要知道hashCode的作用,java中的hashCode的作用主要是用增加哈希存储结构(HashMap HashTable之流)的查找速度,这些哈希存储结构可以通过hashCode来确定对象在哈希存储结构中的存储位置。通过这么一个作用的描述,我们应该get到以下几点:

1、hashCode作用主要在于增加数据在哈希家族中的查询速度。

2、如果hashCode相等,他们在哈希结构中存储位置相等,但是不是同一个对象!换句话说hashCode相等,调用equals不一定相等。

3、如果equals相等,那么他们的存储位置当然相等,所以hashCode一定也是相等的。

4、根据2、3两条,重写equals方法就一定要重写hashCode方法

5.像hashset这样的存取依靠到hashcode,equals方法的,如果不同时重写两个方法,是会受到影响的

   hashset 的底层是一个hashmap,但是其value是固定的值,借助key的不可重复性质,实现去重。所以插入的方法应该是和hashmap一样,通过计算元素hash值进行计算,选择位置进行插入。加入不重写hashcode方法,那么两个在重写的equals方法上相等的对象,他们hashcode依旧按照object中的 == 进行判断,肯定不一样,所以会被放到不同的位置上,实现不了去重。

 

自己的话总结:根据规则是如果两个对象equals,那么两个对象的hashcode一定相同。此时如果自己重写了equals方法,不去重写hashcode方法的话,默认的object类里面的hashcode 是根据对象的内存地址得来的,就会出现两个对象equals,而hashcode不一致的矛盾

 

public class Demo {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Person p1 = new Person("何建锋",18);
		Person p2 = new Person("何建锋",18);
		Set set = new HashSet<Person>();
		set.add(p1);
		set.add(p2);
		System.err.println(set.size());
	}
 
}

class Person {
	
	private String name;
	private int age;
	
	
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
    public Person() {
		// TODO Auto-generated constructor stub
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
}

如果上面类中不重写hashcode方法,那么该类实例化的对象就是object类中的hashcode,由于重写了equals方法,上述程序中p1和p2两个对象是返回true,也就是一样的。而p1,p2的hashcode不一样,违背了原则。

违背原则有什么后果呢?hashset是可以去重的,相同的对象只存储一个。因为p1,p2是相同的,原本只能是存在1个,而由于不重写hashcode,导致hashcode不一样。hashset在存储时候回去判断hashcode,这样就造成了存了2个相同的对象。所以要重写两个都要重写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值