ホームページ  >  記事  >  Java  >  Javaソースコード解析 Arrays.asListメソッドの詳細説明

Javaソースコード解析 Arrays.asListメソッドの詳細説明

高洛峰
高洛峰オリジナル
2017-02-04 10:11:521396ブラウズ

最近、時間をかけて Java Arrays ツール クラスの asList メソッドのソース コードを分析し、関連情報をオンラインでまとめて記録しました。これが読者の役に立つことを願っています。

配列ツール クラスは、可変長パラメーターまたは配列をリストに変換するために使用できるメソッド asList を提供します。

ソースコードは次のとおりです:

/**
 * Returns a fixed-size list backed by the specified array. (Changes to
 * the returned list "write through" to the array.) This method acts
 * as bridge between array-based and collection-based APIs, in
 * combination with {@link Collection#toArray}. The returned list is
 * serializable and implements {@link RandomAccess}.
 *
 * <p>This method also provides a convenient way to create a fixed-size
 * list initialized to contain several elements:
 * <pre class="brush:php;toolbar:false">
 *  List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
 * 
* * @param a the array by which the list will be backed * @return a list view of the specified array */ @SafeVarargs public static List asList(T... a) { return new ArrayList<>(a); }

問題発見

上記のメソッドの説明に従って、最初にいくつかの例を書いてみましょう:

/**
 * @author wangmengjun
 *
 */
public class ArrayExample {
  
 public static void main(String[] args) {
   
  /**使用变长参数*/
  List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
  System.out.println(array1);
   
  /**使用数组*/
  List<String> array2 = Arrays.asList(new String[] {"Welcome", "to","Java", "world"});
  System.out.println(array2);
 }
 
}

上記のプログラムを実行し、次の内容を出力します。

[Welcome, to, Java, world]
[Welcome, to, Java, world]

気まぐれに、作成したリストに「Cool~~~」という文字列を追加して取得したいと思いました。

/**使用变长参数*/
 List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
 array1.add("Cool~~~");

その結果、UnsupportedOperationException が発生しました:

Exception in thread "main" java.lang.UnsupportedOperationException
 at java.util.AbstractList.add(Unknown Source)
 at java.util.AbstractList.add(Unknown Source)
 at test.ArrayExample.main(ArrayExample.java:36)

信じられないことに、new ArrayLista8093152e673feb7aba1828c43532094(a) によって生成されたリストで、add メソッドを呼び出すときに問題が発生しました。

原因検索

それで問題は、何が起こったのかということです。疑問を念頭に置いて、Arrays.asList で使用される ArrayList がどのようなものかを確認してみましょう。

Arrays の asList メソッドで使用される ArrayList クラスは、java.util.ArrayList クラスではなく、内部定義されたクラスであることがわかりました。

ソース コードは次のとおりです:

/**
  * @serial include
  */
 private static class ArrayList<E> extends AbstractList<E>
   implements RandomAccess, java.io.Serializable
 {
   private static final long serialVersionUID = -2764017481108945198L;
   private final E[] a;
 
   ArrayList(E[] array) {
     if (array==null)
       throw new NullPointerException();
     a = array;
   }
 
   public int size() {
     return a.length;
   }
 
   public Object[] toArray() {
     return a.clone();
   }
 
   public <T> T[] toArray(T[] a) {
     int size = size();
     if (a.length < size)
       return Arrays.copyOf(this.a, size,
                  (Class<? extends T[]>) a.getClass());
     System.arraycopy(this.a, 0, a, 0, size);
     if (a.length > size)
       a[size] = null;
     return a;
   }
 
   public E get(int index) {
     return a[index];
   }
 
   public E set(int index, E element) {
     E oldValue = a[index];
     a[index] = element;
     return oldValue;
   }
 
   public int indexOf(Object o) {
     if (o==null) {
       for (int i=0; i<a.length; i++)
         if (a[i]==null)
           return i;
     } else {
       for (int i=0; i<a.length; i++)
         if (o.equals(a[i]))
           return i;
     }
     return -1;
   }
 
   public boolean contains(Object o) {
     return indexOf(o) != -1;
   }
 }

この内部クラス ArrayList の実装から、抽象クラス java.util.AbstractList1a4db2c2c2313771e5742b6debf617a1 を継承していることがわかりますが、add およびメソッドを削除し、特定の実装を考え出すことはありません。

ただし、デフォルトでは、java.util.AbstractList クラスは、add、set、remove メソッドで UnsupportedOperationException を直接スローします。 AbstractList のソース コードの一部は次のとおりです。

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
  /**
   * Sole constructor. (For invocation by subclass constructors, typically
   * implicit.)
   */
  protected AbstractList() {
  }
 
  public E set(int index, E element) {
    throw new UnsupportedOperationException();
  }
 
  /**
   * {@inheritDoc}
   *
   * <p>This implementation always throws an
   * {@code UnsupportedOperationException}.
   *
   * @throws UnsupportedOperationException {@inheritDoc}
   * @throws ClassCastException      {@inheritDoc}
   * @throws NullPointerException     {@inheritDoc}
   * @throws IllegalArgumentException   {@inheritDoc}
   * @throws IndexOutOfBoundsException   {@inheritDoc}
   */
  public void add(int index, E element) {
    throw new UnsupportedOperationException();
  }
 
  /**
   * {@inheritDoc}
   *
   * <p>This implementation always throws an
   * {@code UnsupportedOperationException}.
   *
   * @throws UnsupportedOperationException {@inheritDoc}
   * @throws IndexOutOfBoundsException   {@inheritDoc}
   */
  public E remove(int index) {
    throw new UnsupportedOperationException();
  }
}

これは、java.util.Arrays クラスの内部クラス ArrayList が add メソッドと delete メソッドをオーバーライドしないためです。そのため、その add メソッドを呼び出すと、 、実際には AbstractList を呼び出します。クラスの add メソッドにより、UnsupportedOperationException が直接スローされます。

同様に、remove メソッドを呼び出すとき、または add メソッドと delete メソッドに関連付けられた他のメソッド (addAll など) を呼び出すときにも、UnsupportedOperationException が発生します。

addAllの例:

/**
 * @author wangmengjun
 *
 */
public class ArrayExample {
 
  public static void main(String[] args) {
 
    /**使用变长参数*/
    List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
    array1.addAll(Arrays.asList("AAA", "BBB"));
  }
 
}

Exception in thread "main" java.lang.UnsupportedOperationException
 at java.util.AbstractList.add(Unknown Source)
 at java.util.AbstractList.add(Unknown Source)
 at java.util.AbstractCollection.addAll(Unknown Source)
 at test.ArrayExample.main(ArrayExample.java:36)

setの例:

/**
 * @author wangmengjun
 *
 */
public class ArrayExample {
 
  public static void main(String[] args) {
 
    /**使用变长参数*/
    List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
    System.out.println(array1);
     
    //将Java替换成hello
    array1.set(2, "hello");
    System.out.println(array1);
  }
 
}

Arraysの内部クラスArrayListがsetメソッドをオーバーライドしているからこそ、上記のプログラムは正常に実行できるのです。次に、UnsupportedOperationException 例外をスローします。

結果は次のとおりです:

[Welcome, to, Java, world]
[Welcome, to, hello, world]

使用シナリオ

上記の例と簡単な分析から、Arrays ツール クラスはメソッドを提供します。 asList の場合、このメソッドを使用して可変長パラメータまたは配列をリストに変換します。

ただし、生成されたリストの長さは固定されており、変更操作 (たとえば、特定の位置の要素の変更) は実行できますが、長さに影響を与える操作 (追加、削除など) は実行できません。 UnsupportedOperationException がスローされます。

Arrays.asList は、すでに配列データまたはいくつかの要素があり、操作の追加や削除を行わずに読み取り操作のみに使用されるリストを迅速に構築する必要があるシナリオに適しています。

既知の配列データに基づいて追加、削除、変更、確認できるリストをすばやく取得したい場合、比較的簡単な方法は次のとおりです:

java.util.ArrayList を再利用してレイヤーをラップします。

/**
 * @author wangmengjun
 *
 */
public class ArrayExample {
 
  public static void main(String[] args) {
 
    /**使用变长参数*/
    List<String> array1 = new ArrayList<>(Arrays.asList("Welcome", "to", "Java", "world"));
    System.out.println(array1);
 
    array1.add("Cool~~~");
    System.out.println(array1);
 
  }
 
}

結果は次のとおりです:

[ようこそ、Java、世界へ]
[ようこそ、Java、世界へ、クール~~~]

読んでいただきありがとうございます。みんなを助けてください、みなさんのサポートに感謝します このサイトからのサポート!

Java ソース コードの分析と Arrays.asList メソッドの詳細な説明については、PHP 中国語 Web サイトに注目してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。