首页 > 编程知识 正文

sublist,java sublist

时间:2023-05-04 15:34:51 阅读:226699 作者:2083

无论是在学习中还是在工作中,对于String类型我们并不陌生,也会经常使用到subString()方法。

使用subString()方法得到子字符串,当子字符串添加一个元素改变时,并不影响原来的字符串。

subString(1,3)包含1索引位置的字符,不包含3索引位置的字符。

看下面的例子,也许你会更加明白!

public classSubStringTest {private staticString str;private staticString subStr;public static voidmain(String[] args) {

str= "01234";

subStr= str.substring(1,3);

print();

subStr+= "5";

System.out.println("----------此时将subStr中添加了一个5----------");

print();

}/*** 输出*/

public static voidprint(){

System.out.println("str = " +str);

System.out.println("subStr = " +subStr);

}

}

结果:

然而,在List集合中有这么一个方法subList()。第一眼看上去和String中的subString()很是相像,这使我们会想当然的认为它们是类似的。如果我们这样想就陷入了误区,空口白牙谁会相信,好了,废话不多说,上菜吧!

importjava.util.ArrayList;importjava.util.List;public classSubListTest {private staticList list;private staticList subList;public static voidmain(String[] args) {

list= newArrayList();

list.add("1");

list.add("2");

list.add("3");

list.add("4");

list.add("5");

subList= list.subList(1,3);

System.out.println("==========对子List修改(增、删、改)之前==========");

print();

System.out.println("==========对子List修改(增、删、改)之后==========");

subList.add("a");

print();

}/*** 输出*/

public static voidprint(){

System.out.println("原List: " +list);

System.out.println("子List: " +subList);

}

}

结果:

从结果来看,由subList()方法得到子List,当子List中添加一个元素a后,原List也跟着增加了。看到这里,我们会有疑问,这是为什么呢?要弄明白这个问题,我们需要来翻一翻源码了。

以ArrayList中的subList()来分析,下面是ArrayList的subList()的源码:

public List subList(int fromIndex, inttoIndex) {

subListRangeCheck(fromIndex, toIndex, size);return new SubList(this, 0, fromIndex, toIndex);

}

该方法返回的是ArrayList的内部类SubList的一个实例,同时也将当前的ArrayList对象作为第一个参数传入该构造方法。我们看一下这个构造方法的源码:

private class SubList extends AbstractList implementsRandomAccess {private final AbstractListparent;

SubList(AbstractListparent,int offset, int fromIndex, inttoIndex) {this.parent =parent;this.parentOffset =fromIndex;this.offset = offset +fromIndex;this.size = toIndex -fromIndex;this.modCount = ArrayList.this.modCount;

}

}

通过这个构造方法的源码可知,在创建这个内部类ArrayList.SubList的实例时,会将外部类ArrayList的引用作为该内部类对象中的parent。也就是说,这个ArrayList.SubList内部类实例中的parent字段会拥有ArrayList对象的一个引用, 只是添加了一定的偏移量而已. 由于 List 中存放的元素都是引用类型, 而非基本类型, 所以, 这个子 List 中的每一个元素所代表的引用, 其实就和原 List 中在相同索引处偏移 fromIndex 位置后的那个位置上的元素所代表的引用, 二者指向的是相同的对象. 我们换用更直白的方式来说, 就是:

假设有1,2,3,4,5这5个字符串,被依次添加到原List中,假设我们将原List称作ListA,这时,这5个对象中的每一个都分别被一个引用指向着,这些引用刚好就是ListA中存放的所有元素。(PS:ListA中存放的元素其实是引用,而不是对象本身)这时对ListA执行了subList(1,3)方法,创建了一个子List,我们将这个子List称作ListB。那么这时,"1","4","5"各自还只是被一个引用指向着,但是"2","3"却分别被两个引用指向着,一个引用来自ListA,一个来自ListB,请看下面表格:

在创建子List(即:ListB)之前,每个String被引用的情况如下:

对象

被指向的引用

被指向的引用的总数

"1"

ListA.get(0)

1

"2"

ListA.get(1)

1

"3"

ListA.get(2)

1

"4"

ListA.get(3)

1

"5"

ListA.get(4)

1

在创建子 List ( 即: listB) 之后, 各个 Integer 对象被引用指向的情况如下:

对象

被指向的引用

被指向的引用的总数

"1"

ListA.get(0)

1

"2"

ListA.get(1)

ListB.get(0)

2

"3"

ListA.get(2)

ListB.get(1)

2

"4"

ListA.get(3)

1

"5"

ListA.get(4)

1

留意红色的字. 在创建了 listB, 也就是子List以后, "2"和"3"对象, 都分别被 listA 和 listB中各有一个引用所指向着. 而且还有个规律: listB 中每一个元素(其实这里的元素是引用, 不是对象本身) 所指向的对象, 都会同时被两个引用所指向着. 所以, 对于这些同时被两个引用所指向的对象来说, 不论是用哪个引用来修改这些对象的值, 或者对他们进行增删, 都将影响到另外一个引用的指向结果.

ListA.get(0)

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。