Java中List集合中subList的坑

Posted 夜空中最亮的星

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中List集合中subList的坑相关的知识,希望对你有一定的参考价值。

参考博主http://blog.csdn.net/xuweilinjijis/article/details/9037635

先看List接口subList方法的javadoc 

 The returned list is backed by this list, so non-structural
* changes in the returned list are reflected in this list, and vice-versa.
* The returned list supports all of the optional list operations supported
* by this list.
可以看到此方法其实就是直接指向原List集合中的元素,只是改变了开始位置和结束为止而已.如果修改返回对象的数据,那么原对象对应的值也会被修改。
看一下List接口具体实现类 ArrayList类,其中的subList方法源码如下
public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);//检查是否越界
        return new SubList(this, 0, fromIndex, toIndex);//返回截取之后的对象
    }

 再接着看一下 SubList类的构造器,JDK源码如下,其实 SubList就是ArrayList中的一个内部类(非静态的),

 private class SubList extends AbstractList<E> implements RandomAccess {
        private final AbstractList<E> parent;//引用调用的父集合
        private final int parentOffset;//父集合的起始位置
        private final int offset;//原对象的起始位置
        int size;//现在集合的大小

        SubList(AbstractList<E> parent,
                int offset, int fromIndex, int toIndex) {
            this.parent = parent;//从此处可以看到父集合一直被子集合引用着,只要子集合存在,父集合就不会被释放。从而容易造成内存溢出
            this.parentOffset = fromIndex;
            this.offset = offset + fromIndex;
            this.size = toIndex - fromIndex;
            this.modCount = ArrayList.this.modCount;
        }
}

  下面是一段造成内存溢出的代码

 List<List<Integer>> cache = new ArrayList<List<Integer>>();
        try {

            while (true) {
                ArrayList<Integer> list = new ArrayList<>();
                for(int j=0;j<100000;j++) {
                    list.add(j);
                }
                List<Integer> subList = list.subList(0, 1);
                cache.add(subList);
            }

        } catch (Exception e) {

        }finally {
            System.out.println("Cache Size=" + cache.size());
        }

  运行结果

      Exception in thread "main" Cache Size=815
      java.lang.OutOfMemoryError: GC overhead limit exceeded
     at java.lang.Integer.valueOf(Integer.java:832)
    at com.effectJava.Chapter2.InstrumentedHashSet.main(InstrumentedHashSet.java:44)

看到只包含815个元素就内存溢出啦。就是因为子对象一只引用着父对象,导致父对象无法回收。从而内存溢出

 

     















以上是关于Java中List集合中subList的坑的主要内容,如果未能解决你的问题,请参考以下文章

ArrayList的subList方法带来的坑

List集合中subList方法带的2个参数是啥意思

java 中List.subList 总结

List集合中subList()方法带的2个参数是啥意思

java subList方法小记

Java List的SubList使用问题