为什么 Arrays.asList(...).toArray().getClass() 在 JDK 8 和 9 中给出不同的结果?

Why does Arrays.asList(...).toArray().getClass() give different results in JDK 8 and 9?

为什么下面的条件 return true 和 JDK 8,而 returns false 和 JDK 9?

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

我会说这是 JDK 8 中的一个错误,之前的版本已修复。

List<T>.toArray() 总是被声明为 returning Object[](见 JavaDoc)——实际上它在 return String[]一个特殊情况是一个错误。

asList返回的List类型是Arrays$ArrayList。 JDK 8 中 class 中的 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() returns String[]和JDK 9+中returns Object[], 所以在 JDK 9+ 你的表达式将计算为 false.

这个变化的原因来自JDK-6260652,动机是:

The Collection documentation claims that

collection.toArray()

is "identical in function" to

collection.toArray(new Object[0]);

However, the implementation of Arrays.asList does not follow this: If created with an array of a subtype (e.g. String[]), its toArray() will return an array of the same type (because it use clone()) instead of an Object[].

If one later tries to store non-Strings (or whatever) in that array, an ArrayStoreException is thrown.

因此进行此更改是为了修复以前的行为。


如果这对您来说是个问题,相关的 release note 提供了这个解决方法:

If this problem occurs, rewrite the code to use the one-arg form toArray(T[]), and provide an instance of the desired array type. This will also eliminate the need for a cast.

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