java ArrayList补充——subList
2015-12-02 16:22
513 查看
首先看一个关于subList的问题:下面这段代码的输出结果是什么?
如果认为答案是1 2 3,那么就错了,正确答案是1 2 5 3
那么问题是,为什么对sub插入的数据同时会影响到原本的list中
下面从源码角度解释这个问题:
subList方法的确会产生一个新的List不错,然而这个新的List并不完全是一个新的List,也就是说,新的List和原先的List并没有完全脱离,而是通过偏移量对原本的List进行管理,当执行add操作时候,依旧是插入到原先的List当中。
subList方法并不是ArrayList中的方法,而是其父类AbstractList中提供的方法。
它的源码如下:
如果说调用此方法的List是一个RandomAccess实例,将返回一个RandomAccessSubList,否则返回一个SubList。
RandomAccessSubList与SubList均是AbstractList的内部类,而前者很简单,它是后者的子类,区别在于实现了RandomAccess接口,那么最终要通过查看SubList类中的代码才能理解subList方法的具体情况。(在此暂不讨论RandomAccess)
SubList类的构造方法及该类中的变量:
在做出一系列合法性判断后,只是做了简单的赋值。此处的 l 即为原始的list, offset是fromIndex, size是toIndex - fromIndex,即总长度, expectedModCount初值为l.modCount
在之前代码中:
执行这两句代码后,sub执行的其实是SubList中的add方法,那么这个add方法做了什么,如下:
在这个add方法中,首先调用了 l 的add方法,随即修改了size的值,也就是说,SubList只是对原来的List进行了管理,而并不是单独的List
看看它的get方法:
return的结果是 l 的 index+offset位置的元素值
综上,subList方法获得的List并不是截取出的一个List,而是通过对原来的List做了封装,提供了一些方法来管理,通过偏移量来进行控制,因此一旦改变subList,原来的List同时发生变动。
List<Integer> list = new ArrayList<Integer>(); list.add(1); list.add(2); list.add(3); List<Integer> sub = list.subList(0, 2); sub.add(5); for (Integer i : list) { System.out.print(i.intValue() + "\t"); }
如果认为答案是1 2 3,那么就错了,正确答案是1 2 5 3
那么问题是,为什么对sub插入的数据同时会影响到原本的list中
下面从源码角度解释这个问题:
subList方法的确会产生一个新的List不错,然而这个新的List并不完全是一个新的List,也就是说,新的List和原先的List并没有完全脱离,而是通过偏移量对原本的List进行管理,当执行add操作时候,依旧是插入到原先的List当中。
subList方法并不是ArrayList中的方法,而是其父类AbstractList中提供的方法。
它的源码如下:
public List<E> subList(int fromIndex, int toIndex) { return (this instanceof RandomAccess ? new RandomAccessSubList<E>(this, fromIndex, toIndex) : new SubList<E>(this, fromIndex, toIndex)); }
如果说调用此方法的List是一个RandomAccess实例,将返回一个RandomAccessSubList,否则返回一个SubList。
RandomAccessSubList与SubList均是AbstractList的内部类,而前者很简单,它是后者的子类,区别在于实现了RandomAccess接口,那么最终要通过查看SubList类中的代码才能理解subList方法的具体情况。(在此暂不讨论RandomAccess)
SubList类的构造方法及该类中的变量:
private AbstractList<E> l; private int offset; private int size; private int expectedModCount; SubList(AbstractList<E> list, int fromIndex, int toIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); if (toIndex > list.size()) throw new IndexOutOfBoundsException("toIndex = " + toIndex); if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); l = list; offset = fromIndex; size = toIndex - fromIndex; expectedModCount = l.modCount; }
在做出一系列合法性判断后,只是做了简单的赋值。此处的 l 即为原始的list, offset是fromIndex, size是toIndex - fromIndex,即总长度, expectedModCount初值为l.modCount
在之前代码中:
List<Integer> sub = list.subList(0, 2); sub.add(5);
执行这两句代码后,sub执行的其实是SubList中的add方法,那么这个add方法做了什么,如下:
public void add(int index, E element) { if (index<0 || index>size) throw new IndexOutOfBoundsException(); checkForComodification(); l.add(index+offset, element); expectedModCount = l.modCount; size++; modCount++; }
在这个add方法中,首先调用了 l 的add方法,随即修改了size的值,也就是说,SubList只是对原来的List进行了管理,而并不是单独的List
看看它的get方法:
public E get(int index) { rangeCheck(index); checkForComodification(); return l.get(index+offset); }
return的结果是 l 的 index+offset位置的元素值
综上,subList方法获得的List并不是截取出的一个List,而是通过对原来的List做了封装,提供了一些方法来管理,通过偏移量来进行控制,因此一旦改变subList,原来的List同时发生变动。
相关文章推荐
- Mybatis插入多条相同记录
- Java枚举
- spring调用存储过程
- springMVC return "中文乱码"解决方法
- 将android studio项目转换成eclipse
- java多线程
- 图文来教你在eclipse下用gradle 来打包Android
- PowerDesigner(八)-面向对象模型(用例图,序列图,类图,生成Java源代码及Java源代码生成类图)
- Spring--quartz中cronExpression配置说明
- Spring MVC 3.1新特性 生产者、消费者请求限定
- 几种封装javaBean的方法
- Spring事务传播性与隔离级别
- Java内存模型
- Eclipse标准格式化代码快捷键Ctrl+Shift+F失效
- 转载Eclipse卡顿优化
- java各种日期类型转换操作及讲解
- 关于xampp与navicat在myeclipse上数据库的设置
- JAVA对list集合进行排序Collections.sort()
- spring架构生成二维码
- Java 虚拟机体系结构