配列を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=newArrayList<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
//中略publicstatic<T>List<T>asList(T...a){returnnewArrayList<>(a);}privatestaticclassArrayList<E>extendsAbstractList<E>implementsRandomAccess,java.io.Serializable{privatestaticfinallongserialVersionUID=-2764017481108945198L;privatefinalE[]a;// ←←←finalになってる!ArrayList(E[]array){a=Objects.requireNonNull(array);// 参照コピー(追記)}@Overridepublicintsize(){returna.length;}//中略}
Arraysクラスの内部クラスに定義された簡易版のArrayListを返していた!
※E[] aには元の配列が参照コピーされる。 (追記)
addメソッドの定義がなく、AbstractList.add(E e)にいくため、UnsupportedOperationExceptionが発生していた。
java.util.AbstractList.class
publicbooleanadd(Ee){add(size(),e);returntrue;}//中略publicvoidadd(intindex,Eelement){thrownewUnsupportedOperationException();}
修正
ListToArray.java
//中略ArrayList<String>arrayList=newArrayList<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()は型変換するだけで、参照先メモリ領域もそのままということですね。 (追記)