SubListは一体どうやってArayListに転化しますか?

16406 ワード

SubList
皆さん、こんにちは、今日はトニーさんにSubList転化の穴を教えてあげます。
この間違いは本当に無視されます。皆さん、よく見てください。この間違いは私達の生産環境に本当に遭遇しました。
集合タイプはみんなよく知っていると信じています。JavaではArayListが使うシーンがとても一般的です。今日は主にArayListのsubList方法を見ます。
まずソースを見に来ました。

Returns a view of the potion of this list between the specified{@code from Index}は、inclusive、and{@code toIndex}は、exclusive.

jdkのソースコードの中ではっきりと書いて返したのはnew SubListで、方法の注釈は上に書いてあるのは1つのViewを返すので、ビューと理解することができます。
public List subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);
    return new SubList(this, 0, fromIndex, toIndex);
}
続いて、私達は更に細品のSubListを使って、ソースコードです。

private class SubList extends AbstractList implements RandomAccess {
      private final AbstractList parent;
      private final int parentOffset;
      private final int offset;
      int size;

      SubList(AbstractList 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;
  }
}
SubListはArayListの中の一つの内部類であり、Abstraact Listを継承し、RandomAccessを実現しました。上のコードから見れば、SubListという構造方法で直接引用した親類の要素は、単純に切り取ったインデックスを再作成しただけです。
使用シーン
    public static void main(String[] args) {
    List names = new ArrayList() {{
        add("  ");add("  ");add("` ");
    }};
    List subList = names.subList(0, 3);
    System.out.println(subList);
}
上のコード出力結果
[  ,   ,  ]
どのような状況で誤報がありますか?次に例を見て、上のコードを簡単に修正して、データをArayListに戻します。

  public static void main(String[] args) {
      List names = new ArrayList() {{
        add("  ");add("  ");add(" ");
      }};
      ArrayList 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
なぜ直接ArayListに変換できないですか?上のソースコードはすでに示されていますが、SubListは内部のクラスだけで、Abstraact ListとArayListを引き継ぐのはまったく関係がないので、直接にCastの異常を報告します。
ModificationException
SubListは、追加、削除などのセット元の方法を有する。ソースの一部を切り取ります。
 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();
}
ソースの中ではっきり書いています。元のタイプを判断すると、父のタイプのオリジナルのArayListと現在のSubListの方法の要素の個数を比較することができます。違ったら異常を報告します。1、subListビューのデータの削除
public static void main(String[] args) {
    List namesList = new ArrayList() {{
        add("  ");
        add("  ");
        add(" ");
    }};
    System.out.println("namesList   :== ==>" + namesList);
    List 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、ArayListにデータの削除をする
 public static void main(String[] args) {
    List namesList = new ArrayList() {{
        add("  ");
        add("  ");
        add(" ");
    }};
    System.out.println("namesList   :== ==>" + namesList);
    List 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)
私たちは父要素ArayListにおいてデータを削除操作すると、SubListがConccurrent Modification Exception異常を報告します。この異常はデータの比較発見要素が変更されたことです。汚いデータとして理解できますか?
締め括りをつける
1、SubListとArayListの間には何の関係もありません。
2、SubListをArayListに転化しないでください。異常を報告します。
3、SubListビュー要素の修正は、元の親ArayListのデータに影響を及ぼします。
4、ArayListデータ削除の追加などの修正、SubListはModification異常を報告します。
実際には、SubListは一つのビューとして理解できますが、内部カテゴリであり、その実装は元のArayListで切り取りインデックス位置を変更したものです。
ビューの操作結果は元のArayListに反映されます。元のArayListにデータを追加して削除すると、すみません、今のSubListは異常です。
通俗的に、息子を改正することができます。父を改正することができません。
結果
SubListはArayListに変換し、Guavaにおけるパッケージ方法を使用することができる。Lists.newArrayList(subList)またね