Java提高配(三七)―

         我们常常使用subString方法来对String对象进行分割处理,同时我们也能够使用subList、subMap、subSet来对List、Map、Set进行分割处理,但是这个分割存在某些瑕疵。

1、subList返回仅仅只是1个视图

        首先我们先看以下实例:

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

//通过构造函数新建1个包括list1的列表 list2
List<Integer> list2 = new ArrayList<Integer>(list1);

//通过subList生成1个与list11样的列表 list3
List<Integer> list3 = list1.subList(0, list1.size());

//修改list3
list3.add(3);

System.out.println("list1 == list2:" + list1.equals(list2));
System.out.println("list1 == list3:" + list1.equals(list3));
}

        这个例子非常简单,不过就是通过构造函数、subList重新生成1个与list11样的list,然后修改list3,最后比较list1 == list2?、list1 == list3?。依照我们常规的思路应当是这样的:由于list3通过add新增了1个元素,那末它肯定与list1不等,而list2是通过list1构造出来的,所以应当相等,所以结果应当是:

list1 == list2:true
list1 == list3: false

        首先我们先不论结果的正确与否,我们先看subList的源码:

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

        subListRangeCheck方式是判断fromIndex、toIndex是不是合法,如果合法就直接返回1个subList对象,注意在产生该new该对象的时候传递了1个参数 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的内部类,它与ArrayList1样,都是继承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等都是在原列表上面做操作,它并没有像subString1样生成1个新的对象。所以subList返回的只是原列表的1个视图,它所有的操作终究都会作用在原列表上。

        那末从这里的分析我们可以得出上面的结果应当恰恰与我们上面的答案相反:

list1 == list2:false
list1 == list3:true

Java细节(3.1):subList返回的只是原列表的1个视图,它所有的操作终究都会作用在原列表上

2、subList生成子列表后,不要试图去操作原列表

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

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

//通过subList生成1个与list11样的列表 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());
}

        该实例如果不产生意外,那末他们两个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异常,看过我另外一篇博客的同仁肯定对这个异常非常,fail-fast?不错就是fail-fast机制,在fail-fast机制中,LZ花了很多力气来说述这个异常,所以这里LZ就不对这个异常多讲了(更多请点这里:Java提高篇(34)―

波比源码 – 精品源码模版分享 | www.bobi11.com
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 本站源码并不保证全部能正常使用,仅供有技术基础的人学习研究,请谨慎下载
8. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!

波比源码 » Java提高配(三七)―

发表评论

Hi, 如果你对这款模板有疑问,可以跟我联系哦!

联系站长
赞助VIP 享更多特权,建议使用 QQ 登录
喜欢我嘛?喜欢就按“ctrl+D”收藏我吧!♡