ArrayList.subList方法的

Posted xplj2013

tags:

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

在平时,需要取出集合中一部分数据时。通常会使用subList 

举个例子:

             

List<String> list=new  ArrayList<>();
        
        list.add("d");
        list.add("33");
        list.add("44");
        list.add("55");
        list.add("66");
        
        List<String> list2 = list.subList(0, 2);
        
        System.out.println(list.size());//5
        System.out.println(list2.size());//2

ArrayList.subList返回的是其内部类 SubList 的实例(原始列表的一个视图)。

对原来的list和返回的list做的“非结构性修改”(non-structural changes),都会影响到对方。
所谓的“非结构性修改”是指不涉及到list的大小改变的修改。相反,结构性修改,指改变了list大小的修改。

  • 如果发生结构性修改的是返回的子list,那么原来的list的大小也会发生变化;
  • 而如果发生结构性修改的是原来的list(不包括由于返回的子list导致的改变),那么返回的子list语义上将会是undefined。在AbstractList(ArrayList的父类)中,undefined的具体表现形式是抛出一个ConcurrentModificationException。

这也很好理解,在Java的继承体系中,父类永远不知道自己有没有/有多少子类。

 

取出来的子集长度只有2.查看源代码。

public List<E> subList(int fromIndex, int toIndex) {
        return (this instanceof RandomAccess ?
                new RandomAccessSubList<>(this, fromIndex, toIndex) :
                new SubList<>(this, fromIndex, toIndex));
    }

  注意这里传的this非常重要,直接将原始list传进去了
.........

跟到最后都是SubList<E>

class SubList<E> extends AbstractList<E> {
    private final AbstractList<E> l;
    private final int offset;
    private int size;
 
    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;
        this.modCount = l.modCount;
    }
 
    public E set(int index, E element) {
        rangeCheck(index);
        checkForComodification();
        return l.set(index+offset, element);
    }
 
    public E get(int index) {
        rangeCheck(index);
        checkForComodification();
        return l.get(index+offset);
    }
 
    public int size() {
        checkForComodification();
        return size;
    }
 
    public void add(int index, E element) {
        rangeCheckForAdd(index);
        checkForComodification();
        l.add(index+offset, element);
        this.modCount = l.modCount;
        size++;
    }

  将原始list赋给SubList<E>中的AbstractList<E> l;然而截取的子集长度是size = toIndex - fromIndex;

其实就是到toIndex-1索引的值,举例:list.subList(0, 2)。不是0、1、2三个,子集只是索引0和1的值

 

大家注意在进行子集add等方法的时候都进行了AbstractList<E> l的操作。所以出现了下面的情况,子集添加时原始list也进行了增加

List<String> list=new  ArrayList<>();
		
		list.add("d");
		list.add("33");
		list.add("44");
		list.add("55");
		list.add("66");
		
		List<String> list2 = list.subList(0, 2);
		list2.add("77");
		
		System.out.println(list.size());//6
		System.out.println(list2.size());//3

  强调:使用sublist()返回的只是原list对象的一个视图,因此Sublist内部类和ArrayList的内部保存数据的地址是一样得;即它们在内存中是同一个List(集合),只是parentOffset ,size等参数不同

      1.如果达到的效果要对子集进行操作,原始list不改变。建议以下方式:

            List<Object> tempList = new ArrayList<Object>(list.subList(2, lists.size()));

    tempList.add("xxxxx");

2.我们可以方便的使用如下代码来删除某个区间的序列。
list.subList(from, to).clear();

--------------------- 本文来自 ypp91zr 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/ypp91zr/article/details/52117814?utm_source=copy 






以上是关于ArrayList.subList方法的的主要内容,如果未能解决你的问题,请参考以下文章

ArrayList#subList这四个坑,一不小心就中招

从源码角度解析ArrayList.subList的几个坑

从源码角度解析ArrayList.subList的几个坑

VSCode自定义代码片段—— 数组的响应式方法

VSCode自定义代码片段10—— 数组的响应式方法

Android课程---Android Studio使用小技巧:提取方法代码片段