web-dev-qa-db-ja.com

Arrays.asList(...)。toArray()。getClass()がJDK 8と9で異なる結果を与えるのはなぜですか?

次の条件がJDK 8ではtrueを返すのに、JDK 9ではfalseを返すのはなぜですか?

String[].class == Arrays.asList("a", "b").toArray().getClass()
44
Felix

Listによって返されるasListタイプは Arrays$ArrayList です。そのクラスのJDK 8のtoArrayメソッドは次のとおりです。

@Override
public Object[] toArray() {
    return a.clone();
}

ただし、JDK 9以降では次のようになります。

@Override
public Object[] toArray() {
    return Arrays.copyOf(a, a.length, Object[].class);
}

どちらの場合もString[]asListに渡されますが、JDK 8の場合は複製され、その配列型(String[])が保持され、JDK 9+ではコピーされますArrays.copyOfの明示的な新しい配列タイプでObject[]を使用します。

この違いは、JDK 8 Arrays.asList("a", "b").toArray().getClass()ではString[]を返し、JDK 9+ではObject[]を返すため、JDK 9+では式はfalseに評価されます。

この変更の理由は、 JDK-6260652 の動機によるものです。

コレクションのドキュメントでは、

collection.toArray()

「機能的に同一」である

collection.toArray(new Object[0]);

ただし、Arrays.asListの実装はこれに従いません。サブタイプの配列(たとえばString[])で作成された場合、そのtoArray()は同じ型の配列を返します(なぜならObject[]の代わりにclone())を使用します。

後でその配列に非文字列(またはその他)を保存しようとすると、ArrayStoreExceptionがスローされます。

この変更は、以前の動作を修正するために行われました。


これがあなたにとって問題であれば、関連する リリースノート は回避策としてこれを提供します:

この問題が発生した場合、1引数形式toArray(T[])を使用するようにコードを書き直し、目的の配列タイプのインスタンスを提供します。これにより、キャストも不要になります。

String[] array = list.toArray(new String[0]);
51
Jorn Vernee

これはJDK 8のバグであり、それが修正される前のことです。

List<T>.toArray()は常にObject[]を返すと宣言されていました( JavaDoc を参照)-特別な場合にString[]を返すことは間違いでした。

12
Thomas Kläger