package cn.sunzn.memoryleak; import java.util.Collection; import java.util.Collections; import java.util.HashSet; /** * HashSet 的底层是由 HashMap 实现的,HashSet 存储的值会被当作 HashMap 中的 Key 来存储同时 * 这个 Key 会和一个固定的充当 Value 的值共同组成一个 Entry,这个 Entry 会调用 hashCode()方法 * 计算出一个 hashCode 值作为这个 Entry 的属性。当存入下一个值的时候 HashSet 内部会计算当前存 * 入的值和固定的 Value 值组成的 Entry 的 hashCode 值并和上一个存入值的 hashCode 属性进行比 * 对,如果不同,则存入;如果相同则不存入。如果这时将存入值的 Key 进行修改,然而对应的hashCode * 属性值却不会因为 Key 值的改变而重新计算,而是会保留开始存入时计算好的 hashCode 值。这时再存 * 入和被修改后相同的 HashSet 值进去的时候,程序会对这个新存入的 HashSet 值和固定的 Value 值 * 组成的 Entry 计算出新的 hashCode 值进和上一个修改后的 Entry 进行比对,然而,上一个存入的值 * 保存了未修改前的 hashCode 值,这时就会出现有相同的值存入 HashSet 的情况。但是这时如果要存入 * 和第二个值修改前相同的值,就会出现不能存入的现象,因为它们会计算出相同的 hashCode 值。 */ public class ReflectTest { public static void main(String[] args) { Collection<ReflectPoint> collection = new HashSet<ReflectPoint>(); ReflectPoint point1 = new ReflectPoint(3, 3); ReflectPoint point2 = new ReflectPoint(3, 5); ReflectPoint point3 = new ReflectPoint(3, 3); ReflectPoint point4 = new ReflectPoint(3, 7); Collections.addAll(collection, point1, point2, point3); System.out.println("HashSet 的长度:" + collection.size()); point1.setY(7); System.out.println("HashSet 的长度:" + collection.size()); collection.add(point4); System.out.println("HashSet 的长度:" + collection.size()); System.out.println("point1 的 hashCode 值:" + point1.hashCode()); System.out.println("point4 的 hashCode 值:" + point4.hashCode()); System.out.println("point1 和 point4 的 equals 比较:" + point1.equals(point4)); System.out.println("point1 和 point4 的内存地址比较:" + (point1 == point4)); System.out.println(collection); collection.add(point1); System.out.println("HashSet 的长度:" + collection.size()); } }
运行结果: HashSet 的长度:2 HashSet 的长度:2 HashSet 的长度:3 point1 的 hashCode 值:1061 point4 的 hashCode 值:1061 point1 和 point4 的 equals 比较:true point1 和 point4 的内存地址比较:false [ReflectPoint [x=3, y=5], ReflectPoint [x=3, y=7], ReflectPoint [x=3, y=7]] HashSet 的长度:3
下面的代码为上面 ReflectTest 类用到的 ReflectPoint 类:
package cn.sunzn.memoryleak; public class ReflectPoint { private int x; private int y; public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } public int hashCode() { final int prime = 31; int result = 1; result = prime * result + x; result = prime * result + y; return result; } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; ReflectPoint other = (ReflectPoint) obj; if (x != other.x) return false; if (y != other.y) return false; return true; } public String toString() { return "ReflectPoint [x=" + x + ", y=" + y + "]"; } }