当前位置:   article > 正文

sublist方法_SubList到底怎么转化为ArrayList?

sublist转arraylist

06932647b3a763d3579e1a531596a16f.png

SubList

大家好,今天Tony给大家讲个SubList转化的坑。

这个错误真的会被忽略,大家好好的看看,这个错误我们生产环境还真的遇到过。

集合类型相信大家都很熟悉,在Java中ArrayList使用的场景非常普遍。我们今天主要看的是ArrayList中的subList 方法。

首先我们来看看源码

Returns a view of the portion of this list between the specified {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.

在jdk的源码中清楚的写明了返回的是一个new SubList,方法的注释上面写的是返回一个View,可以理解为视图吗?

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

接下里我们再细品SubList,源码

  1. private class SubList extends AbstractList<E> implements RandomAccess {
  2. private final AbstractList<E> parent;
  3. private final int parentOffset;
  4. private final int offset;
  5. int size;
  6. SubList(AbstractList<E> parent,
  7. int offset, int fromIndex, int toIndex) {
  8. this.parent = parent;
  9. this.parentOffset = fromIndex;
  10. this.offset = offset + fromIndex;
  11. this.size = toIndex - fromIndex;
  12. this.modCount = ArrayList.this.modCount;
  13. }
  14. }

SubList 是ArrayList中的一个内部类,继承了AbstractList,实现了RandomAccess,从上面的代码中可以看到,在SubList这个构造方法中还是直接引用的父类中的元素,只是单纯的将截取的索引重新赋值了一下。

使用场景

  1. public static void main(String[] args) {
  2. List<String> names = new ArrayList<String>() {{
  3. add("兔子");
  4. add("托尼");
  5. add("啊");
  6. }};
  7. List<String> subList = names.subList(0, 3);
  8. System.out.println(subList);
  9. }

上面的代码输出结果

[兔子, 托尼, 啊]

在什么情况下会报错呢?接下来再看个例子,把上面的代码简单修改下,让数据返回ArrayList

  1. public static void main(String[] args) {
  2. List<String> names = new ArrayList<String>() {{
  3. add("兔子");
  4. add("托尼");
  5. add("啊");
  6. }};
  7. ArrayList<String> subList = (ArrayList)names.subList(0, 3);
  8. System.out.println(subList);
  9. }

上面的代码直接抛出异常了

Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList$SubList cannot be cast to java.util.ArrayList

为什么不能直接转换为ArrayList呢?上面的源码已经显示了,SubList只是一个内部类,它继承AbstractList 和ArrayList 根本都没有关系,所以直接转化会报Cast异常。

ModificationException

SubList同样具有集合原属都方法比如添加、删除等。我截取部分源码。

  1. public E set(int index, E e) {
  2. rangeCheck(index);
  3. checkForComodification();
  4. E oldValue = ArrayList.this.elementData(offset + index);
  5. ArrayList.this.elementData[offset + index] = e;
  6. return oldValue;
  7. }
  8. public E get(int index) {
  9. rangeCheck(index);
  10. checkForComodification();
  11. return ArrayList.this.elementData(offset + index);
  12. }
  13. public int size() {
  14. checkForComodification();
  15. return this.size;
  16. }
  17. public void add(int index, E e) {
  18. rangeCheckForAdd(index);
  19. checkForComodification();
  20. parent.add(parentOffset + index, e);
  21. this.modCount = parent.modCount;
  22. this.size++;
  23. }
  24. public E remove(int index) {
  25. rangeCheck(index);
  26. checkForComodification();
  27. E result = parent.remove(parentOffset + index);
  28. this.modCount = parent.modCount;
  29. this.size--;
  30. return result;
  31. }
  32. protected void removeRange(int fromIndex, int toIndex) {
  33. checkForComodification();
  34. parent.removeRange(parentOffset + fromIndex,
  35. parentOffset + toIndex);
  36. this.modCount = parent.modCount;
  37. this.size -= toIndex - fromIndex;
  38. }
  39. ```
  40. 上面等源码中每一个方法都包含有一个 checkForComodification 方法。
  41. 这个方法是有什么作用呢?
  42. ```java
  43. private void checkForComodification() {
  44. if (ArrayList.this.modCount != this.modCount)
  45. throw new ConcurrentModificationException();
  46. }

源码中写的很清楚,判断原始类型,可以理解为父类型原始的ArrayList和当前的SubList方法中的元素个数做比较,如果不一样就报异常。 1、 对subList视图做数据的删除

  1. public static void main(String[] args) {
  2. List<String> namesList = new ArrayList<String>() {{
  3. add("兔子");
  4. add("托尼");
  5. add("啊");
  6. }};
  7. System.out.println("namesList原始的:== ==>" + namesList);
  8. List<String> subList = namesList.subList(0, 2);
  9. System.out.println("subList截取的:== ==>" + subList);
  10. //删除SubList第2个元素
  11. subList.remove(1);
  12. System.out.println("subList删除的:== ==>" + subList);
  13. System.out.println("namesList删除的:== ==>" + namesList);
  14. }

上面的代码运行正常输出结果

  1. namesList原始的:== ==>[兔子, 托尼, 啊]
  2. subList截取的:== ==>[兔子, 托尼]
  3. subList删除的:== ==>[兔子]
  4. namesList删除的:== ==>[兔子, 啊]

2、 对ArrayList做数据的删除

  1. public static void main(String[] args) {
  2. List<String> namesList = new ArrayList<String>() {{
  3. add("兔子");
  4. add("托尼");
  5. add("啊");
  6. }};
  7. System.out.println("namesList原始的:== ==>" + namesList);
  8. List<String> subList = namesList.subList(0, 2);
  9. System.out.println("subList截取的:== ==>" + subList);
  10. //删除ArraList第2个元素
  11. namesList.remove(1);
  12. System.out.println("subList删除的:== ==>" + subList);
  13. System.out.println("namesList删除的:== ==>" + namesList);
  14. }

输出结果报异常了

  1. namesList原始的:== ==>[兔子, 托尼, 啊]
  2. subList截取的:== ==>[兔子, 托尼]
  3. Exception in thread "main" java.util.ConcurrentModificationException
  4. at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231)
  5. at java.util.ArrayList$SubList.listIterator(ArrayList.java:1091)
  6. at java.util.AbstractList.listIterator(AbstractList.java:299)
  7. at java.util.ArrayList$SubList.iterator(ArrayList.java:1087)
  8. at java.util.AbstractCollection.toString(AbstractCollection.java:454)
  9. at java.lang.String.valueOf(String.java:2994)
  10. at java.lang.StringBuilder.append(StringBuilder.java:131)

当我们对父元素ArrayList中对数据进行删除操作的时候,我们会发现subList会报一个 ConcurrentModificationException异常,这个异常是对数据比较发现元素被更改过,可以理解为脏数据吗?

总结

1、 SubList 和 ArrayList之间没有任何关系

2、千万不要将SubList转化为ArrayList会报转换异常

3、对SubList视图元素对修改会影响原始对父ArrayList中对数据。

4、对ArrayList数据对删除添加等修改,SubList会报Modification异常

其实我们可以理解下,SubList理解为一个视图,其实就是一个内部类,它的实现就是在原始的ArrayList中改变了截取的索引位置。

对视图的操作结果会反映到原始的ArrayList中,如果对原始的ArrayList做数据的添加删除操作,不好意思此刻的SubList已经报异常了。

通俗一点,可以修改儿子,不能修改父亲。

SubList转化为ArrayList可以用Guava中的封装方法

Lists.newArrayList(subList)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/982303
推荐阅读
相关标签
  

闽ICP备14008679号