Java集合类hashCode错误之StackOverflowError

      前段时间写bantouyan-json代码,偶然发现Java集合类的一个问题,就是一旦集合中出现了循环引用,调用hashCode方法就会触发StackOverflowError错误。一般情况下集合内不会出现循环引用,但Java集合并不禁止这样做,从具体应用上讲,循环引用的情况也有可能出现。但是,一旦直接或间接调用hashCode方法,就会导致StackOverflowError,我不清楚Java这样设计是一个失误还是这种情况没有必要处理,但它的存在会给代码设计带来一定的问题。

 

      我当时的情况是想用HashSet存储一个ArraList对象,代码是这样写的:

ArrayList<Object> list = new ArrayList<Object>();
list.add(list);
HashSet<Object> set = new HashSet<Object>();
set.add(list);
//Exception in thread "main" java.lang.StackOverflowError
//                    at java.util.AbstractList$Itr.next(AbstractList.java:345)
//                    at java.util.AbstractList.hashCode(AbstractList.java:526)
//                    at java.util.AbstractList.hashCode(AbstractList.java:527)

结果测试时就冒出了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集合设计的一个失误。既然应用中有可能出现集合间的循环引用,就应该避免这种错误出现。

 

你可能感兴趣的:(java,thread,json)