突っ走り書き

見せるほどのものでは..

Arrays.asList の戻り値は ArrayList でも LinkedList でもない

Java の Arrays は,配列のためのユーティリティクラスです.
痒いところに手が届く関数がたくさんあるので思いのほか使えます.
その中で特に重宝してるのが Arrays.asList です.
これを使うとリストの生成と初期化をスタイリッシュに書くことができます.

// スマート!
List<String> l1 = Arrays.asList("one", "two", "three");

// Arrays.asList を使わないと...
List<Stirng> l2 = new ArrayList<>();
l2.add("one");
l2.add("two");
l3.add("three);

ところで,Arrays.asList が生成するリストの実装クラスは ArrayList と LinkedList のどちらでしょうか?
調べてみます.

List<String> l = Arrays.asList("one", "two", "three");
		
System.out.println(l instanceof List);       // => true
System.out.println(l instanceof ArrayList);  // => false!
System.out.println(l instanceof LinkedList); // => false!!

List ではあるけれど ArrayList でも LinkedList でもないという結果に.
そんな謎のリストは,おっかなくて使う気になりません.

さらに,次のコードでは UnsupportedOperationException が発生します.

String[] array = {"one", "two", "three"};
Arrays.asList(array).add("one");    // => 例外発生
Arrays.asList(array).remove("one"); // => 例外発生

調べてみると,Arrays.asList の戻り値は,

  • Arrays 内で定義された内部クラス ArrayList

を返すようです.
なぜ,add/remove が例外をスローするかというと,
Arrays$ArrayListjava.util.AbstractList から継承した add/remove をオーバーライドしていないからです.
java.utl.AbstractList の add/remove は次のように定義されています.

public void add(int index, E element) {
    throw new UnsupportedOperationException();
}

public E remove(int index) {
    throw new UnsupportedOperationException();
}

Arrays$ArrayList はこのメソッドをオーバーライドしないため,例外がスローされます.

実装クラスは配列によるリストであると判明したので,そのつもりで使おうと思います.