Java Array initialization with type casting

The following code makes me confused:

Object[] arr1 = new String[]{"a", "b", "c"};
Object[] arr2 = {"a", "b", "c"};

String[] a = (String[]) arr1; // ok
String[] b = (String[]) arr2; // ClassCastException

System.out.println(arr1.getClass().getName()); // [Ljava.lang.String;
System.out.println(arr2.getClass().getName()); // [Ljava.lang.Object;

I am trying to understand why the two initialization are different from each other. The first one is a post declaration, while the second one is a shortcut. The two are both declared as Object[]

My naive understanding is that:

Object[] arr2 = {"a", "b", "c"}; // is a syntax sugar of
Object[] arr2 = new Object[] {"a", "b", "c"};

So the runtime type of arr2 is exactly Object[] which can not be converted into String[].

But the things get strange here, because Java Array is covariant: String[] is a subclass of Object[] and arr2 is exactly a String[], casting back from Object[] to String[] on arr2 should work.

Any explanation on this is high appreciated.

Jon Skeet
people
quotationmark

arr2 is exactly a String[]

No, it isn't - it's an Object[], as you said - your line is equivalent to:

Object[] arr2 = new Object[] {"a", "b", "c"};

It's an Object[] which happens to have elements which are all string references at the moment... but you could also write:

arr2[0] = new Object(); // Fine, because arr2 is an Object[]

If you did the same thing with arr1, you'd get an exception:

arr1[0] = new Object(); // Fine at compile time, will throw an exception

You can check the actual execution-time type of an object using getClass of course:

System.out.println(arr2.getClass());

people

See more on this question at Stackoverflow