どのようにArrayListのに最後にサブリスト?

サブリスト

みなさん、こんにちは、今日トニーはあなたに教えてSubListピットの転換を。

このエラーは、実際にこのエラーは本当に私たちの生産環境を満たし、我々は良い見て、無視されます。

私たちは、非常に一般的なJavaのArrayListに使用される場面のコレクションの種類に精通していると信じています。私たちは、主に、今日は、ArrayListをするのsubList方法でご覧ください。

まず、ソースで見てみましょう

戻り指定{@codeたfromIndex}、包括的、および{@codeたtoIndex}、排他的との間のこのリストの部分のビューを。

JDKソースに明確の戻りに記載されるnew SubList方法上記書き込みコメント表示を返すことで、ビューを理解することができます。

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

我々ファインケミカル次にSubList、ソースコード


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;
  }
}

サブリストが継承されたAbstractList内の内部クラスのArrayListで、ランダム・を達成するため、この設定のサブリスト方式または直接参照される要素で、親クラス、上記のコードから見ることができ、簡単に再インデックス取られます割り当てAはビット。

利用シナリオ

    public static void main(String[] args) {
    List<String> names = new ArrayList<String>() {{
        add("兔子");add("托尼");add("`啊");
    }};
    List<String> subList = names.subList(0, 3);
    System.out.println(subList);
}

上記のコード出力

[兔子, 托尼, 啊]

どのような状況下でそれを文句を言うのだろうか?次に、例を見ては、上記のコードは単純な変形例であり、データはArrayListのを返してみましょう


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

上記のコードは、直接投げ

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

なぜ直接ArrayListにそれを変換することはできませんか?上記のソースは、継承のArrayList AbstractListことを、サブリストだけで内部クラスを示されており、単に問題で、それが直接変換されたキャストの例外が報告されますされません。

ModificationException

サブリストはまた、追加、削除、などなどのプリミティブメソッドのコレクションを持っています。Iソースコードのインターセプト一部。

 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;
  }

  public E get(int index) {
      rangeCheck(index);
      checkForComodification();
      return ArrayList.this.elementData(offset + index);
  }

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

  public void add(int index, E e) {
      rangeCheckForAdd(index);
      checkForComodification();
      parent.add(parentOffset + index, e);
      this.modCount = parent.modCount;
      this.size++;
  }

  public E remove(int index) {
      rangeCheck(index);
      checkForComodification();
      E result = parent.remove(parentOffset + index);
      this.modCount = parent.modCount;
      this.size--;
      return result;
  }

  protected void removeRange(int fromIndex, int toIndex) {
      checkForComodification();
      parent.removeRange(parentOffset + fromIndex,
                         parentOffset + toIndex);
      this.modCount = parent.modCount;
      this.size -= toIndex - fromIndex;
  }

上記の方法源の各々は、前記checkForComodification方法。このアプローチはどのような影響ですか?

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

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

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

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

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

2、 对 ArrayList 做数据的删除

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

输出结果报异常了

namesList原始的:== ==>[兔子, 托尼, 啊]
subList截取的:== ==>[兔子, 托尼]
Exception in thread "main" java.util.ConcurrentModificationException
    at java.util.ArrayList$SubList.checkForComodification(ArrayList.java:1231)
    at java.util.ArrayList$SubList.listIterator(ArrayList.java:1091)
    at java.util.AbstractList.listIterator(AbstractList.java:299)
    at java.util.ArrayList$SubList.iterator(ArrayList.java:1087)
    at java.util.AbstractCollection.toString(AbstractCollection.java:454)
    at java.lang.String.valueOf(String.java:2994)
    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)

下次见!

おすすめ

転載: www.cnblogs.com/tonyY/p/12296344.html