java ArrayList补充——subList

首先看一个关于subList的问题:下面这段代码的输出结果是什么?

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

RandomAccessSubListSubList均是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;
    }

在做出一系列合法性判断后,只是做了简单的赋值。此处的 即为原始的list, offsetfromIndex, sizetoIndex - 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方法中,首先调用了 add方法,随即修改了size的值,也就是说,SubList只是对原来的List进行了管理,而并不是单独的List

看看它的get方法:

public E get(int index) {
        rangeCheck(index);
        checkForComodification();
        return l.get(index+offset);
    }

return的结果是 的 index+offset位置的元素值

 

综上,subList方法获得的List并不是截取出的一个List,而是通过对原来的List做了封装,提供了一些方法来管理,通过偏移量来进行控制,因此一旦改变subList,原来的List同时发生变动。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值