Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why can't cast Object[] to String[]

  1. No error

    Object[] a = new String[]{"12","34","56"};
    String[] b = (String[]) a;
    
  2. No error

    Object a = new String[]{"12","34","56"};    
    String[] b = (String[]) a;
    
  3. Run time error : ClassCastException

    Object[] a = new Object[3];
    a[0] = "12";
    a[1] = "34";
    a[2] = "56";
    String[] b = (String[]) a;
    
  4. Run time error : ClassCastException

    Object[] a = {"12","34","56"};    
    String[] b = (String[]) a;
    

Of course, we can downcast an Object[] variable back to String[] if it was created as an String[].

My question is why we can not cast Object[] to String[] when it was created as Object[] but all its members are String? Is it because of security reason or just not that useful to implement this?

like image 465
Don Li Avatar asked Aug 08 '13 06:08

Don Li


3 Answers

Here's two reasons I can think of.

Firstly, if you change the original array, the casted array can become invalid. e.g.

 Object[] a = {"12","34","56"};   
 String[] b = (String[]) a; // pretend this is legal. a and b now point to the same array

 a[0] = new Object(); // clearly ok
 String x = b[0]; // No longer a string! Bad things will happen!

Secondly, the example you have chosen is very simple, but if you have a very large Object[] array and it's not clear to the compiler what is filling it, then it has no way of validating that every element of the array satisfies the cast.

Object[] a = new Object[10000];
// lots of weird and whacky code to fill the array with strings

String[] b= (String[]) a; // valid or no? The best-defined answer is to say no.
like image 55
Alex MDC Avatar answered Oct 12 '22 02:10

Alex MDC


It is defined in the JLS #5.5.3. In substance, a cast:

 r = new RC[]; TC[] t = (TC[]) r;

"works" at runtime iif RC is a subtype of TC (or TC itself). Whether RC actually only contains TCs is irrelevant and the compile-time type of r is not used either (what matters is the runtime type):

  • you can write: r = new String[]; Object[] t = (Object[]) r;, but
  • you can't write r = new Object[]; String[] t = (String[]) r;.

JLS extract:

If T is an array type TC[], that is, an array of components of type TC, then a run-time exception is thrown unless one of the following is true:

  • TC and RC are the same primitive type.
  • TC and RC are reference types and type RC can be cast to TC by a recursive application of these run-time rules for casting.

In your examples 3 and 4, RC = Object and TC = String and Object is not a subtype of String. In your examples 1 and 2, RC = String and TC = String so it works.

Note: the type in this context is the runtime type.

like image 34
assylias Avatar answered Oct 12 '22 00:10

assylias


Because you are not casting individual member of array, you are casting the whole array instance which is of type Object[] and not String[].

Object[] a = new String[]{"12","34","56"};

Here the instance is of type String[] and the compile time type is Object[].

And in the next line you are casting it back to String[] which is allowed as the actual type or runtime type is String[].

But Object[] a = new Object[3]; here the actual type and Compile time type is Object[] and it is not String[]. So an Object[] cannot be String[].

Object[] a = new Object[1];
a[0] = "a"; //Actual type String 

So you can do this:

String aStr = (String)a[0];
like image 25
Narendra Pathai Avatar answered Oct 12 '22 00:10

Narendra Pathai