Why is List<String>.toArray().getClass() giving different results in JDK 1.8 and 11

  • A+
Category:Languages

Why does the following condition return true with JDK 1.8.0_131, whereas it returns false with JDK 11.0.1.

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 11 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 it's array type (String[]), and in jdk 11 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 11 it returns Object[], so in jdk 11 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[]), 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.

So this change was made to fix the previous behaviour.

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: