今天在看Hashtable的toString()源码时,看到了其中有一个”key == this”的判断,于是突发奇想,如果用Hashtable添加自身再做一些别的操作会怎样?
①,hashCode方法
先看代码:
1 public static void main(String[] args) { 2 Hashtable table = new Hashtable(); 3 table.put(table, 1); 4 System.out.println(table.hashCode()); 5 9 }
如果我们运行这段代码,好,正常运行,输出1。
接下来再用HashMap试一下同样的代码:
1 public static void main(String[] args) { 2 HashMap map = new HashMap(); 3 map.put(map, map); 4 System.out.println(map.hashCode()); 5 }
运行,结果:
竟然出StackOverFlowException异常了!这是为什么呢?
来分别看看他们的代码:
Hashcode的源代码如下:
1 public synchronized int hashCode() { 2 /* 3 * This code detects the recursion caused by computing the hash code 4 * of a self-referential hash table and prevents the stack overflow 5 * that would otherwise result. This allows certain 1.1-era 6 * applets with self-referential hash tables to work. This code 7 * abuses the loadFactor field to do double-duty as a hashCode 8 * in progress flag, so as not to worsen the space performance. 9 * A negative load factor indicates that hash code computation is 10 * in progress. 11 */ 12 int h = 0; 13 if (count == 0 || loadFactor < 0) 14 return h; // Returns zero 15 16 loadFactor = -loadFactor; // Mark hashCode computation in progress 17 Entry[] tab = table; 18 for (int i = 0; i < tab.length; i++) 19 for (Entry e = tab[i]; e != null; e = e.next) 20 h += e.key.hashCode() ^ e.value.hashCode(); 21 loadFactor = -loadFactor; // Mark hashCode computation complete 22 23 return h; 24 }
看了代码是不是一目了然了呢。代码里面有一个guard来阻止了死循环。
就是loadFactor = -loadFactor;就是说代码调用key(就是hashtable自身)的hashCode时,此时loadFactor已经成了负值,那么就直接返回0了,所以不会一直死循环下去。
而HashMap却没有这个guard来阻止死循环,所以就崩掉了。
②,remove方法
先上代码:
1 public static void main(String[] args) { 2 Hashtable table = new Hashtable(); 3 table.put(table, 1); 4 System.out.println(table); 5 table.remove(table); 6 System.out.println(table); 7 }
运行结果如下:
{(this Map)=1}
{(this Map)=1}
很明显,remove方法没有把里面的table删掉,why?
其实,remove方法执行时,要找到这个table在内部数组中的位置,查找的依据就是key的hashCode,代码如下:
for (int i = 0; i < tab.length; i++)
for (Entry e = tab[i]; e != null; e = e.next)
h += e.key.hashCode() ^ e.value.hashCode();
因为table已经发生了变化,所以其hashCode值也发生了变化,跟之前插进去的时候的值已经不一样了,所以就删除不掉了。
原创文章,作者:Maggie-Hunter,如若转载,请注明出处:https://blog.ytso.com/19419.html