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

风流意气都作罢 提交于 2019-12-04 19:31:26

问题


  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?


回答1:


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.



回答2:


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.




回答3:


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];



回答4:


Array objects are not just a collection of their elements, they have classes just like other objects. The class for array of strings is a subclass of array of objects. That's why there's no error in your 1 or 2, but the last two are equivalent to

Object o = new Object();
String s = (String) o;



回答5:


If all members Object array were Strings at the moment of casting you still could assign objects that are not Strings to the elements of this array later. So you would have String array with elements which are not Strings.




回答6:


This post provides a way to quickly create a String[] out of an Object[].

arrayOfUrls = imageUrls.toArray(new String[imageUrls.size()]);

Assuming of course that imageUrls is not null.



来源:https://stackoverflow.com/questions/18119494/why-cant-cast-object-to-string

工具导航Map