Java Array initialization with type casting
Asked Answered
L

4

14

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.

Leralerch answered 29/7, 2015 at 12:41 Comment(1)
"arr2 is exactly a String[]" It's an Object[]. It appears that they are only strings in it, but it stills an Object[]. Try to do arr1[1] = 1;, you will have an ArrayStoreException at runtime as it's really a String[] behind, but arr2[1] = 1; works fine as it's an Object[].Snowshed
S
6

Because arr2 is an Object[], there's nothing stopping you from writing

arr2[0] = new Object();

right before your cast, case in which the cast would no longer make sense anyway.

Because of the way initializer syntax works, also note the following:

Object x = {"a", "b"}; // error: illegal initializer for Object
Object[] a = {"a", "b"}; //a has class [Ljava.lang.Object; 
String[] b = {"a", "b"};  //b has class [Ljava.lang.String; 

The compiler determines whether you want your array to be an Object[] or a String[] based on your declaration.

Seduce answered 29/7, 2015 at 12:46 Comment(1)
There's also nothing stopping you from writing arr1[0] = new Object();.Fireworm
L
5

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());
Lycaon answered 29/7, 2015 at 12:46 Comment(0)
J
3

Almost correct. Your logic is flawed here:

arr2 is exactly a String[]

No, it is not. It is an array of Objects. The fact that you just added Strings into this array is meaningless. You could have written

arr2 = {"a", new Integer(5) };

too.

Probably that makes it more clear, why you are not allowed to cast such an array to String[].

Jacobah answered 29/7, 2015 at 12:47 Comment(0)
H
1
Object[] arr2 = {"a", "b", "c"};

In this case, the array you declared is equal to

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

So, the elements in arr2 can be any type of Object. And at the line

String[] b = (String[]) arr2; // ClassCastException

Because you are trying cast whole Object[] to a String[].

Where as in the first you are explicitly telling all the Objects are Strings

Object[] arr1 = new String[]{"a", "b", "c"};
Headman answered 29/7, 2015 at 12:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.