复杂对象作为Map的key导致内存溢出问题

复杂对象作为map的key时,如果修改了对象中某些字段的值,必导致内存泄露,是因为这个节点存储的地址未改变,但这个因为对象的字段改变导致hashcode发生改变,所以map.get(obj),map.containsKey(obj),map.remove(obj)都无法访问到该对象,会变成死对象,称之为内存泄露,大量的内存泄露会导致内存溢出。解决方案:要修改的对象的字段,不参与hashcode的计算,即重写hashcode和equals方法。

总结:HashMap在使用可变对象作为key是一件很危险的事情,解决办法重写hashcode方法和equals方法

比较两个对象是否相等时需要调用对象的equals()方法,即判断对象引用所指向的对象地址是否相等,对象地址相等时,

Object类的源码可以看出,默认的equals 判断的是两个对象的引用指向的是不是同一个对象;而hashcode也是根据对象地址生成一个整数数值;

当我们重写一个类的 equals 方法时就应当连同重写 hashcode 方法,并且两个方法应满足:

1:一致性,即:当两个对象 equals 比较为 true,那么 hashcode 值应当相等,反之亦然,因为当两个对象hashcode 值相等,但是 equals 比较为 false,那么在 HashMap 中会产生链表,影响查询性能。

2:成对重写,即重写 equals 就应当重写 hashcode。

为什么覆盖equals方法时总要覆盖hashCode方法?

因为如果不这么做的话,就违反了Object.hashCode的通用约定,导致该类无法结合所有基于散列的集合(HashMap,HashSet,HashTable)一起正常运作.

在应用程序执行期间,只要equals方法的比较操作用到的信息没变,那么对这同一个对象调用多次,hashCode方法都必须始终如一的返回同一个整数.但在应用程序的多次执行中,即重新启动后结果可以不一致.

如果两个对象根据equals比较是相等的,那这两个对象调用hashCode方法返回的结果必须是一样的.

如果两个对象根据equals比较是不相等,那这两个对象调用hashCode方法返回的结果不一定不同.但不同的对象产生不同的hasCode,可以提高散列表的性能.

不覆盖hashCode而违反的关键约定是第二条:相等的对象必须具有相等的hashCode.

如果相同的对象具有不同的hashCode,那么将对象放入hashMap中,对象会被存放到不同的桶中,当去get 时,虽然是同一个对象,但是由于生成的hashCode不同,会到不同的桶中去找,此时便找不到那个对象。

在程序执行期间,只要equals方法的比较操作用到的信息没有被修改,那么对这同一个对象调用多次,hashCode方法必须始终如一地返回同一个整数。

如果两个对象根据equals方法比较是相等的,那么调用两个对象的hashCode方法必须返回相同的整数结果。

如果两个对象根据equals方法比较是不等的,则hashCode方法不一定得返回不同的整数。

所以在不覆盖equals方法时,使用equals方法和==的比较结果是一样的。

一个Native Method方法就是一个JAVA调用非JAVA代码的接口,native这个方法实现在C++中

因为 Set 存储的是不重复的对象,依据 hashCode 和 equals 进行判断,所以 Set 存储的 对象必须重写这两个方法。

1)HashSet集合排重时,需要判断两个对象是否相同,对象相同的判断可以通过hashCode值判断,所以需要重写hashCode()方法

2)hashset不能为一样的,放入一个值首先判断hashcode(类似下标)是否已经存在,然后用equals判断是否有一样的值。

3)如果只重写其中一个方法的时候,向HashSet集合中添加多个对象时,所有属性都相同时,并没有完成想要的排重效果。hashset不能为一样的,放入一个值首先判断hashcode(内存中的位置)是否已经存在,然后用equals判断是否有一样的值。

猜你喜欢

转载自www.cnblogs.com/shineipangtuo/p/12396016.html