0

Can someone explain to me:

List<String> wordsList = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
String[] wordsArray = (String[]) wordsList.toArray();

This fall with: Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;

 List<String> wordsList = Arrays.asList("one", "two", "three");        
 String[] wordsArray = (String[]) wordsList.toArray();

Now is OK! What is the difference??

2 Answers2

2

toArray() is the old way of doing things, back in I think 1.5 the preferred way is to use toArray(T[])

List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
String [] words = list.toArray(new String[] {});
System.out.println(Arrays.toString(words));
Ryan
  • 1,762
  • 6
  • 11
  • 2
    The preferred way today would be `list.toArray(String[]::new)`. – David Conrad Apr 26 '22 at 21:52
  • 1
    @DavidConrad fair enough. I'm still learning the newer features and many of the projects I'm on mandate a lower compile level so I don't get into the habit of using the newer features. It's aggravating. – Ryan Apr 27 '22 at 16:24
  • I feel your pain. My company is using Java 8. I use recent versions on my own to keep up with the newer features. – David Conrad Apr 27 '22 at 17:24
0

List.toArray returns an Object[]. This type cannot, in general, be cast down to a String[]. In fact, no guarantee is made that it is a String[]. In your Arrays.asList example, it looks like List<String> was able to take the existing array you passed it and make a (runtime) String[], but that's an implementation detail and is subject to change at any time (and, based on the comments, is not even consistent across Java versions).

The reason the function returns an Object[] rather than a T[] is because of type erasure. The type T is not available at runtime, so we can't construct instances of T or T[]. However, there's an overload of toArray which will put the values into a T[], but you have to supply the array. This gets around the problem of not being able to write new T[], since it's your job as the caller to supply the array, so no new allocation needs to take place.

String[] tmpArray = new String[10]; // Just an initial guess as to the size
String[] wordsArray = list.toArray(tmpArray); // Note: No cast necessary

wordsArray might be the same as tmpArray, or it might be an extended data structure constructed from tmpArray. Either way, the original tmpArray should be regarded as destroyed at that point and not used anymore.

Note: The fact that String[] is even a subtype of Object[] (i.e. that the cast you suggested ever works) is a consequence of a questionable decision that the Java team made to make arrays covariant, when really a mutable data structure like that should be invariant, mathematically speaking.

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116