带你走进Java集合_ArrayList源码深入分析4

上一篇我们主要讲解了ArrayList的迭代器,我们首先归纳一下ArrayList迭代器的主要内容:

1.迭代器主要利用游标cursor来遍历集合的,游标cursor主要指向下一个元素的下标。所以cursor是关键。
2.迭代器在迭代的时候可以察觉到fast-fail.
3.Itr的游标只能向后移动,所以只能向后遍历,而ListIterator既可以向前移动也可以向后移动

这一篇文章我们从源码角度讲解ArrayList的最后一个知识点:SubList

从字面上可以知道是ArrayList的子元素,所以SubList也会提供删、改、查,迭代的功能,我们要牢记一个知识点:subList不是从ArrayList复制一份,而是SubList指向的实例是ArrayList的一段映射,ArrayList的修改和SubList的修改是对同一个底层数组的修改。在ArrayList获取subList的方法如下:

public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }

上面的方法有两个参数,fromIndex是映射的开始下标,toIndex是映射的结束下标。其中0<=fromIndex<=toIndex<=size,此方法最后一个元素不包含toIndex,如果fromIndex,toIndex不符合

举例说明:

public static void main(String[] args) throws Exception {
        List<Integer> list = new ArrayList<Integer>();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);
        list.add(5);
        list.add(6);
        list.add(7);
        List<Integer> subList = list.subList(1, 4);
        for (Integer sub : subList) {
            System.out.print(sub + " ");
        }
    }

运行结果如下:


从运算结果中我们可以看到,subList方法包含fromIndex,但是不包含toIndex.

如果fromIndex、toIndex不符合0<=fromIndex<=toIndex<=size公式时,运算的结果是怎样的,例如我们formIndex=1,toIndex=10,运算结果:


所以,调用ArrayList的subList(fromIndex,toIndex)方法时,要时刻记住0<=fromIndex<=toIndex<=size这个公式。

我总结了SubList有一下两个特性:

特性1.SubList是ArrayList集合的一段映射,而不是拷贝。
特性2.要牢记这个公式:0<=fromIndex<=toIndex<=size

现在我们从SubList的源码来分析上面的的两个特性

SubList是ArrayList的一个内部类,

1.SubList的重要属性如下:

第一个重要的属性:AbstractList<E> parent:这个就是ArrayList

第二个重要的属性:int parentOffset:映射到ArrayList的开始下标

第三个重要的属性:int offset:subList的开始下标,其实在ArrayList中parentOffset=offset.从下面源码可以证明:

 public List<E> subList(int fromIndex, int toIndex) {
        subListRangeCheck(fromIndex, toIndex, size);
        return new SubList(this, 0, fromIndex, toIndex);
    }
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;
        }

参数offset=0,所以parentOffset=offset

SubList提供了如下方法,总结一下,调用这些方法时,都不能修改ArrayList,否则就会抛出异常。每一个方法都会首先调用checkForComodification()检查一下:

private void checkForComodification() {
            if (ArrayList.this.modCount != this.modCount)
                throw new ConcurrentModificationException();
        }

第一个方法:E set(int index, E e)

public E set(int index, E e) {
            rangeCheck(index);
            checkForComodification();
            E oldValue = ArrayList.this.elementData(offset + index);
            ArrayList.this.elementData[offset + index] = e;
            return oldValue;
        }

1)rangeCheck(index)就是判断给出的索引是否有效

2)checkForComodification()就是判断调用set的时候是否修改的ArrayList元素。

3)从第三句可以看出,直接修改ArrayList集合的元素

从这个方法中就可以证明特性1所说的,SubList是ArrayList一段映射,而不是复制。

下面的方法和set类似,只要读过ArrayList的同学都不难理解,在这里就不做解释了。

这篇文章主要介绍了ArrayList中的一个方法subList(fromIndex,toIndex),我们记住SubList的两个特性后,就能够驾驭subList方法了

特性1.SubList是ArrayList集合的一段映射,而不是拷贝。
特性2.要牢记这个公式:0<=fromIndex<=toIndex<=size















  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值