运行结果:
删除前的大小size:3
删除后的大小size:3
擦,发现一个问题了,而且是个大问题呀,我们调用了remove删除r3对象,以为删除了r3,但事实上并没有删除,这就叫做内存泄露,就是不用的对象但是他还在内存中。所以我们多次这样操作之后,内存就爆了。看一下remove的源码:
/**
* Removes the specified element from this set if it is present.
* More formally, removes an element e such that
* (o==null e==null : o.equals(e)),
* if this set contains such an element. Returns true if
* this set contained the element (or equivalently, if this set
* changed as a result of the call). (This set will not contain the
* element once the call returns.)
*
* @param o object to be removed from this set, if present
* @return true if the set contained the specified element
*/
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
然后再看一下remove方法的源码:
/**
* Removes the mapping for the specified key from this map if present.
*
* @param key key whose mapping is to be removed from the map
* @return the previous value associated with key, or
* null if there was no mapping for key.
* (A null return can also indicate that the map
* previously associated null with key.)
*/
public V remove(Object key) {
Entry
e = removeEntryForKey(key);
return (e == null null : e.value);
}
在看一下removeEntryForKey方法源码:
/**
* Removes and returns the entry associated with the specified key
* in the HashMap. Returns null if the HashMap contains no mapping
* for this key.
*/
final Entry
removeEntryForKey(Object key) {
int hash = (key == null) 0 : hash(key);
int i = indexFor(hash, table.length);
Entry
prev = table[i]; Entry
e = prev; while (e != null) { Entry
next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; size--; if (prev == e) table[i] = next; else prev.next = next; e.recordRemoval(this); return e; } prev = e; e = next; } return e; }
其实上面的方法实现很简单的:如下图:

很简单的一个线性的hash表,使用的hash函数是mod,源码如下:
/**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
return h & (length-1);
}这个其实就是mod运算,只是这种运算比%运算要高效。
1,2,3,4,5表示是mod的结果,每个元素对应的是一个链表结构,所以说想删除一个Entry
上面的这个内存泄露告诉我一个信息:如果我们将对象的属性值参与了hashCode的运算中,在进行删除的时候,就不能对其属性值进行修改,否则会出现严重的问题。
其实我们也可以看一下8种基本数据类型对应的对象类型和String类型的hashCode方法和equals方法。
其中8中基本类型的hashCode很简单就是直接返回他们的数值大小,String对象是通过一个复杂的计算方式,但是这种计算方式能够保证,如果这个字符串的值相等的话,他们的hashCode就是相等的。8种基本类型的equals方法就是直接比较数值,String类型的equals方法是比较字符串的值的。