Why does the following condition return true
with JDK 8, whereas it returns false
with JDK 9?
String[].class == Arrays.asList("a", "b").toArray().getClass()
The List
type returned by asList
is Arrays$ArrayList
. The toArray
method in JDK 8 on that class is:
@Override
public Object[] toArray() {
return a.clone();
}
But in JDK 9+ it is:
@Override
public Object[] toArray() {
return Arrays.copyOf(a, a.length, Object[].class);
}
In both cases a String[]
is passed to asList
, but in the JDK 8 case it is cloned, which retains its array type (String[]
), and in JDK 9+ it is copied using Arrays.copyOf
with the explicit new array type of Object[]
.
This difference means that in JDK 8 Arrays.asList("a", "b").toArray().getClass()
returns String[]
and in JDK 9+ it returns Object[]
, so in JDK 9+ your expression will evaluate to false
.
The reason for this change comes from JDK-6260652 with the motivation:
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[]
), itstoArray()
will return an array of the same type (because it useclone()
) instead of anObject[]
.If one later tries to store non-Strings (or whatever) in that array, an
ArrayStoreException
is thrown.
So this change was made to fix the previous behaviour.
If this is a problem for you, the related release note offers this as a work-around:
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]);