Java集合类hashCode错误之StackOverflowError
????? 前段时间写bantouyan-json代码,偶然发现Java集合类的一个问题,就是一旦集合中出现了循环引用,调用hashCode方法就会触发StackOverflowError错误。一般情况下集合内不会出现循环引用,但Java集合并不禁止这样做,从具体应用上讲,循环引用的情况也有可能出现。但是,一旦直接或间接调用hashCode方法,就会导致StackOverflowError,我不清楚Java这样设计是一个失误还是这种情况没有必要处理,但它的存在会给代码设计带来一定的问题。
?
????? 我当时的情况是想用HashSet存储一个ArraList对象,代码是这样写的:
结果测试时就冒出了StackOverflowError错误,是由于间接调用AbstractList的hashCode方法引起的。查看Java的API文档,AbstractList的hashCode是把每一个子元素的hashCode经过迭代计算得到的,也就是说,要计算AbstractList的hashCode,就要把每一个子元素的hashCode先计算一遍,如果这些子元素中的某一个或子元素的子元素引用到上级对象,那么hashCode方法就会出现无限递归调用,最终出现StackOverflowError错误。
?
????? 经检查,不光是List,其他集合对象,如Map、Set、Stack等也有这个问题,即他们的hashCode也是通过计算子元素的hashCode得到的。也就是说,无论是List,还是Map、Set,只要内部出现了循环引用,如一个List引用了一个Map,Map又引用了顶层的List,调用hashCode方法就会导致堆栈溢出错误。
?
????? 这种错误出现的几率非常低,但存在这样的问题不能不说是Java集合设计的一个失误。既然应用中有可能出现集合间的循环引用,就应该避免这种错误出现。
?
1 楼 guibin 2011-03-20 第二行代码,为什么要新建一个list,然后自己把自己加进去?这样做有什么特殊的用途吗? 2 楼 裴小星 2011-03-20 guibin 写道第二行代码,为什么要新建一个list,然后自己把自己加进去?这样做有什么特殊的用途吗?
为了测试循环引用吧,自己引用自己。我觉得一般也不会这么做。 3 楼 bantouyan 2011-03-28 裴小星 写道guibin 写道第二行代码,为什么要新建一个list,然后自己把自己加进去?这样做有什么特殊的用途吗?
为了测试循环引用吧,自己引用自己。我觉得一般也不会这么做。
你说的对,只是一个测试而已,现实中谁也不会这么做,但有可能出现间接引用。