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

Fel*_*lix 44 java java-8 java-9

为什么以下条件返回trueJDK 8,而它返回falseJDK 9?

String[].class == Arrays.asList("a", "b").toArray().getClass()
Run Code Online (Sandbox Code Playgroud)

Jor*_*nee 51

List返回的类型asListArrays$ArrayList.在toArray对类在JDK 8的方法是:

@Override
public Object[] toArray() {
    return a.clone();
}
Run Code Online (Sandbox Code Playgroud)

但在JDK 9+中它是:

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

在这两种情况下String[]都传递给a 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文档声称

collection.toArray()
Run Code Online (Sandbox Code Playgroud)

是"功能相同"

collection.toArray(new Object[0]);
Run Code Online (Sandbox Code Playgroud)

但是,实现Arrays.asList并不遵循:如果使用子类型数组(例如String[])创建,toArray()它将返回相同类型的数组(因为它使用clone())而不是Object[].

如果后来尝试在该数组中存储非字符串(或其他),ArrayStoreException则抛出一个.

所以这个改变是为了修复以前的行为.


如果这对您来说是一个问题,相关的发行说明提供了解决此问题的方法:

如果出现此问题,请重写代码以使用one-arg表单toArray(T[]),并提供所需数组类型的实例.这也将消除演员阵容的需要.

String[] array = list.toArray(new String[0]);
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是[`ArrayList(Collection)`构造函数](http://hg.openjdk.java.net/jdk6/jdk6/jdk/file/8deef18bb749/src/share/classes/java/util/ArrayList.java #l144)包含对这种不良行为的保护,参考这个错误报告(它来自2005年)很长一段时间,而没有人首先想到修复不端行为,显然...... (3认同)

Tho*_*ger 12

我会说这是JDK 8中的一个错误,在此之前已经修复了.

List<T>.toArray()总是被声明为返回Object[](参见JavaDoc) - 它String[]在特殊情况下实际返回是一个错误.

  • 那是不对的.该方法总是返回`Object []`(只看它的返回类型声明).它从未违反其声明的类型.相反,它违反了其记录的运行时行为.区别在于细微差别,但却很重要. (4认同)
  • 关于此更改的JDK 9发行说明如下:https://www.oracle.com/technetwork/java/javase/9​​-notes-3745703.html#JDK-6260652 (2认同)