##配列をArrayListに変換する方法と注意点・落とし穴
配列をArrayListに変換する方法を紹介します。
絶対にハマる落とし穴があるので、最後まで読んでください!
ListToArray.java
String[] array ={"A","B","C"};
List<String> list = Arrays.asList(array);
System.out.println("配列 = " + Arrays.toString(array));
System.out.println("List = " + list.toString());
###結果
配列 = [A, B, C]
List = [A, B, C]
できた!簡単じゃん。
・・・でも
##要素を追加してみる
ListToArray.java
//中略
List<String> list = Arrays.asList(array);
list.add("D"); //Dを追加!
###結果
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
at codeSample.ListToArray.main(ListToArray.java:13)
エラーになる
##なぜか
返すクラスを取得してみる
ListToArray.java
//中略
List<String> list = Arrays.asList(array);
ArrayList<String> arrayList = new ArrayList<String>();
System.out.println("通常のArrayList = " + arrayList.getClass());
System.out.println("配列からの変換 = " + list.getClass());
###結果
通常のArrayList = class java.util.ArrayList
配列からの変換 = class java.util.Arrays$ArrayList
ん、なんか違う!
##深堀してみる
java.util.Arrays.class
//中略
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a; // ←←←finalになってる!
ArrayList(E[] array) {
a = Objects.requireNonNull(array); // 参照コピー(追記)
}
@Override
public int size() {
return a.length;
}
//中略
}
Arraysクラスの内部クラスに定義された簡易版のArrayListを返していた!
※E[] aには元の配列が参照コピーされる。 (追記)
addメソッドの定義がなく、AbstractList.add(E e)にいくため、UnsupportedOperationExceptionが発生していた。
java.util.AbstractList.class
public boolean add(E e) {
add(size(), e);
return true;
}
//中略
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
##修正
ListToArray.java
//中略
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(array));
arrayList.add("D");
System.out.println("配列 = " + Arrays.toString(array));
System.out.println("List = " + arrayList.toString());
新しくArrayListの領域をnewして変換する。 (追記)
###結果
配列 = [A, B, C]
List = [A, B, C, D]
Arrays.asList()は型変換するだけで、参照先メモリ領域もそのままということですね。 (追記)