subList

subList返回仅仅只是一个视图。直接上源码

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

subListRangeCheck方式是判断fromIndex、toIndex是否合法,如果合法就直接返回一个subList对象,注意在产生该new该对象的时候传递了一个参数 this ,该参数非常重要,因为他代表着原始list。

/**
* 继承AbstractList类,实现RandomAccess接口
*/
private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent; //列表
private final int parentOffset;
private final int offset;
int size; //构造函数
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;
} //set方法
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;
} //get方法
public E get(int index) {
rangeCheck(index);
checkForComodification();
return ArrayList.this.elementData(offset + index);
} //add方法
public void add(int index, E e) {
rangeCheckForAdd(index);
checkForComodification();
parent.add(parentOffset + index, e);
this.modCount = parent.modCount;
this.size++;
} //remove方法
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;
this.size--;
return result;
}
}

该SubLsit是ArrayList的内部类,它与ArrayList一样,都是继承AbstractList和实现RandomAccess接口。同时也提供了get、set、add、remove等list常用的方法。但是它的构造函数有点特殊,在该构造函数中有两个地方需要注意:

1、this.parent = parent;而parent就是在前面传递过来的list,也就是说this.parent就是原始list的引用。

2、this.offset = offset + fromIndex;this.parentOffset = fromIndex;。同时在构造函数中它甚至将modCount(fail-fast机制)传递过来了。

我们再看get方法,在get方法中return ArrayList.this.elementData(offset + index);这段代码可以清晰表明get所返回就是原列表offset + index位置的元素。同样的道理还有add方法里面的:

parent.add(parentOffset + index, e);
this.modCount = parent.modCount;

remove方法里面的

E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;

诚然,到了这里我们可以判断subList返回的SubList同样也是AbstractList的子类,同时它的方法如get、set、add、remove等都是在原列表上面做操作,它并没有像subString一样生成一个新的对象。所以subList返回的只是原列表的一个视图,它所有的操作最终都会作用在原列表上

从上面我们知道subList生成的子列表只是原列表的一个视图而已,如果我们操作子列表它产生的作用都会在原列表上面表现,但是如果我们操作原列表会产生什么情况呢?

public static void main(String[] args) {
List<Integer> list1 = new ArrayList<Integer>();
list1.add(1);
list1.add(2); //通过subList生成一个与list1一样的列表 list3
List<Integer> list3 = list1.subList(0, list1.size());
//修改list3
list1.add(3); System.out.println("list1'size:" + list1.size());
System.out.println("list3'size:" + list3.size());//子视图里有modcount比较校验
}

该实例如果不产生意外,那么他们两个list的大小都应该都是3,但是偏偏事与愿违,事实上我们得到的结果是这样的:

list1'size:3
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$SubList.checkForComodification(Unknown Source)
at java.util.ArrayList$SubList.size(Unknown Source)
at com.chenssy.test.arrayList.SubListTest.main(SubListTest.java:17)

list1正常输出,但是list3就抛出ConcurrentModificationException异常。我们再看size方法:

public int size() {
checkForComodification();
return this.size;
}

size方法首先会通过checkForComodification验证,然后再返回this.size。

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

该方法表明当原列表的modCount与this.modCount不相等时就会抛出ConcurrentModificationException。同时我们知道modCount 在new的过程中 "继承"了原列表modCount,只有在修改该列表(子列表)时才会修改该值(先表现在原列表后作用于子列表)。而在该实例中我们是操作原列表,原列表的modCount当然不会反应在子列表的modCount上啦,所以才会抛出该异常。

对于子列表视图,它是动态生成的,生成之后就不要操作原列表了,否则必然都导致视图的不稳定而抛出异常。最好的办法就是将原列表设置为只读状态,要操作就操作子列表:

//通过subList生成一个与list1一样的列表 list3
List<Integer> list3 = list1.subList(0, list1.size()); //对list1设置为只读状态
list1 = Collections.unmodifiableList(list1);

在开发过程中我们一定会遇到这样一个问题:获取一堆数据后,需要删除某段数据。例如,有一个列表存在1000条记录,我们需要删除100-200位置处的数据,我们可以这样处理:

子列表的操作都会反映在原列表上。所以下面一行代码全部搞定:

list1.subList(100, 200).clear();

asList

1.在使用asList时不要将基本数据类型当做参数。

2.asList返回的列表只不过是一个披着list的外衣(Arrays里面的内部类ArrayList),它并没有list的基本特性(变长)。该list是一个长度不可变的列表,传入参数的数组有多长,其返回的列表就只能是多长。

//入参需要是泛型
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
} //基本类型不能当泛型传入,而数组可以,所以个数是一个,类型是数组
public static void main(String[] args) {
int[] ints = {1,2,3,4,5};
List list = Arrays.asList(ints);
System.out.println("list'size:" + list.size());
System.out.println("list 的类型:" + list.get(0).getClass());
System.out.println("list.get(0) == ints:" + list.get(0).equals(ints));
}
--------------------------------------------
outPut:
list'size:1
list 的类型:class [I
list.get(0) == ints:true //正确方式,Integer可以是泛型
public static void main(String[] args) {
Integer[] ints = {1,2,3,4,5};
List list = Arrays.asList(ints);
System.out.println("list'size:" + list.size());
System.out.println("list.get(0) 的类型:" + list.get(0).getClass());
System.out.println("list.get(0) == ints[0]:" + list.get(0).equals(ints[0]));
}
----------------------------------------
outPut:
list'size:5
list.get(0) 的类型:class java.lang.Integer
list.get(0) == ints[0]:true

使用工具类 Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方 法,它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。 说明:asList 的返回对象是一个 Arrays 内部类,并没有实现集合的修改方法。Arrays.asList 体现的是适配器模式,只是转换接口,后台的数据仍是数组。

   String[] str = new String[] { "a", "b" };
   List list = Arrays.asList(str);

第一种情况:list.add("c"); 运行时异常。

第二种情况:str[0]= "jinyong"; 那么 list.get(0)也会随之修改

subList和asList的更多相关文章

  1. Collections类常用方法总结

    1. sort 对集合进行排序 public static <T extends Comparable<? super T>> void sort(List<T> ...

  2. thinking in java之Collections工具类的使用

    代码摘自<thinking in java>4td 此实例非常好的总结了Collections的一些常见方法的使用. package countainers; import java.ut ...

  3. Java 容器在实际项目开发中应用

    前言:在java开发中我们离不开集合数组等,在java中有个专有名词:"容器" ,下面会结合Thinking in Java的知识和实际开发中业务场景讲述一下容器在Web项目中的用 ...

  4. 【Java集合的详细研究1】Collections类常用方法总结

    1.sort(Collection)方法的使用(含义:对集合进行排序). 例:对已知集合c进行排序? public class Practice { public static void main(S ...

  5. Collections常用方法总结

    public class CollectionsTest { public static void main(String[] args) { List<Integer> list = n ...

  6. Java集合操作类Collections的一些常用方法

    public static void main(String[] args) { List<Integer> list = new ArrayList<Integer>(); ...

  7. Java知识点梳理——常用方法总结

    1.查找字符串最后一次出现的位置 String str = "my name is zzw"; int lastIndex = str.lastIndexOf("zzw& ...

  8. Java 学习(21):Java 实例

    Java 实例 本章节我们将为大家介绍 Java 常用的实例,通过实例学习我们可以更快的掌握 Java 的应用. Java 环境设置实例 //HelloWorld.java 文件 public cla ...

  9. Collection 和 Collections的区别

    1.java.util.Collection 是一个集合接口(集合类的一个顶级接口).它提供了对集合对象进行基本操作的通用接口方法.Collection接口在Java 类库中有很多具体的实现.Coll ...

随机推荐

  1. meta中的viewport指令

    网页手机wap2.0网页的head里加入下面这条元标签,在iPhone的浏览器中页面将以原始大小显示,并不允许缩放. <meta name="viewport" conten ...

  2. [置顶] Android应用开发之版本更新你莫愁

    传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229 今天我们学习如何实现Android应用的自动更新版本功能,这是在各种语言编写的应用中都 ...

  3. [Effective JavaScript 笔记] 第7条:视字符串为16位的代码单元序列

    Unicode编码,基础:它为世界上所有的文字系统的每个字符单位分配一个唯一的整数,该整数介于0~1114111之间,在Unicode术语中称为代码点(code point). 和其它字符编码几乎没有 ...

  4. git clone报错

    (文章是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) Could not chdir to home directory /home/wangzheng: ...

  5. ICA

    参考:http://www.cnblogs.com/jerrylead/archive/2011/04/19/2021071.html 对高斯分布的样本点效果不好.数学真是博大精深啊

  6. poj1094

    Sorting It All Out Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 29539   Accepted: 10 ...

  7. HDOJ 1690

    Bus System Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  8. 如何高效利用GitHub

    是Github,让社会化编程成为现实.本文尝试谈谈GitHub的文化.技巧与影响. Q1:GitHub是什么 Q2:GitHub风格 Q3: 在GitHub,如何跟牛人学习 Q4: 享受纯粹的写作与演 ...

  9. 《转》Visual Studio 2010 终极定制安装精简方法

    打开VS2010安装目录下的 Setup 文件夹,找到 baseline.dat 文件和 vs_setup.pdi 文件还有一个 locdata.ini 文件,是对应的. 这些都是文本文件,用记事本就 ...

  10. Java for LeetCode 072 Edit Distance【HARD】

    Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...