subList

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

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

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

  1. /**
  2. * 继承AbstractList类,实现RandomAccess接口
  3. */
  4. private class SubList extends AbstractList<E> implements RandomAccess {
  5. private final AbstractList<E> parent; //列表
  6. private final int parentOffset;
  7. private final int offset;
  8. int size;
  9.  
  10. //构造函数
  11. SubList(AbstractList<E> parent,
  12. int offset, int fromIndex, int toIndex) {
  13. this.parent = parent;
  14. this.parentOffset = fromIndex;
  15. this.offset = offset + fromIndex;
  16. this.size = toIndex - fromIndex;
  17. this.modCount = ArrayList.this.modCount;
  18. }
  19.  
  20. //set方法
  21. public E set(int index, E e) {
  22. rangeCheck(index);
  23. checkForComodification();
  24. E oldValue = ArrayList.this.elementData(offset + index);
  25. ArrayList.this.elementData[offset + index] = e;
  26. return oldValue;
  27. }
  28.  
  29. //get方法
  30. public E get(int index) {
  31. rangeCheck(index);
  32. checkForComodification();
  33. return ArrayList.this.elementData(offset + index);
  34. }
  35.  
  36. //add方法
  37. public void add(int index, E e) {
  38. rangeCheckForAdd(index);
  39. checkForComodification();
  40. parent.add(parentOffset + index, e);
  41. this.modCount = parent.modCount;
  42. this.size++;
  43. }
  44.  
  45. //remove方法
  46. public E remove(int index) {
  47. rangeCheck(index);
  48. checkForComodification();
  49. E result = parent.remove(parentOffset + index);
  50. this.modCount = parent.modCount;
  51. this.size--;
  52. return result;
  53. }
  54. }

该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方法里面的:

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

remove方法里面的

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

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

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

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

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

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

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

  1. public int size() {
  2. checkForComodification();
  3. return this.size;
  4. }

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

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

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

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

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

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

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

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

asList

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

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

  1. //入参需要是泛型
    public static <T> List<T> asList(T... a) {
  2. return new ArrayList<>(a);
  3. }
  4.  
  5. //基本类型不能当泛型传入,而数组可以,所以个数是一个,类型是数组
  6. public static void main(String[] args) {
  7. int[] ints = {1,2,3,4,5};
  8. List list = Arrays.asList(ints);
  9. System.out.println("list'size:" + list.size());
  10. System.out.println("list 的类型:" + list.get(0).getClass());
  11. System.out.println("list.get(0) == ints:" + list.get(0).equals(ints));
  12. }
  13. --------------------------------------------
  14. outPut:
  15. list'size:1
  16. list 的类型:class [I
  17. list.get(0) == ints:true
  18.  
  19. //正确方式,Integer可以是泛型
  20. public static void main(String[] args) {
  21. Integer[] ints = {1,2,3,4,5};
  22. List list = Arrays.asList(ints);
  23. System.out.println("list'size" + list.size());
  24. System.out.println("list.get(0) 的类型:" + list.get(0).getClass());
  25. System.out.println("list.get(0) == ints[0]:" + list.get(0).equals(ints[0]));
  26. }
  27. ----------------------------------------
  28. outPut:
  29. list'size:5
  30. list.get(0) 的类型:class java.lang.Integer
  31. list.get(0) == ints[0]:true

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

  1. String[] str = new String[] { "a", "b" };
  1. 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. ExtJS学习之路第七步:contentEl与renderTo的区别

    上回在Panel的应用中我们应该能大致区分开conteEl和renderTo,这回我们从定义中区分. 在Panel的API中, contentEl:String指定一个现有的HTML元素或者id作为此 ...

  2. 避免使用CSS表达式

    http://www.cnblogs.com/chenxizhang/archive/2013/05/01/3053439.html 这一篇我来和大家讨论个原则:Avoid CSS Expressio ...

  3. 小白科普之JavaScript的函数

    一 概述 1.1 函数声明 (1)function命令 函数就是使用function命令命名的代码区块,便于反复调用.这种声明方式叫做函数的声明(Function Declaration). func ...

  4. Objective-C和其他C指针的转换

    首先看一下典型的NSString与CFStringRef的相互转换   http://www.tuicool.com/articles/MJRr226 // CFStringRef to NSStri ...

  5. rails获取json内容

    文章是从我的个人博客上粘贴过来的, 大家也可以访问 www.iwangzheng.com url点开后的json是这样的 { e:   { provider: ”searches.soku.top”, ...

  6. Correlation Filter in Visual Tracking

    涉及两篇论文:Visual Object Tracking using Adaptive Correlation Filters 和Fast Visual Tracking via Dense Spa ...

  7. Python 脚本之获取CPU信息

    #!/usr/bin/env Python from __future__ import print_function from collections import OrderedDict impo ...

  8. android文章学习 侧滑菜单实现

    http://blog.csdn.net/jj120522/article/details/8075249 http://blog.csdn.net/lilybaobei/article/detail ...

  9. pro git 使用积累

    http://www.zhihu.com/question/20070065 git相关问题的收集 Git 是 Linux 之父 Linus Trovalds,为管理 Linux 内核代码而建立的,被 ...

  10. devstack重启后不能运行

    devstack 重启后没有运行服务. 解释: “Note if you reboot your machine running devstack, you need to rerun stack.s ...