According to JLS 7, 5.1.6 Narrowing Reference Conversion
• From any array type SC[] to any array type TC[], provided that SC and TC are reference types and there is a narrowing reference conversion from SC to TC.
Object[] objArr = {"a","b","c"};
String[] strArr = (String[])objArr; // ClassCastException
in the above example, both objArr and strArr are reference types and there's a narrow reference conversion from Object to String.
Object obj = "a";
String str = (String)obj;
but the following codes works fine:
Object[] objArr = (Object[])java.lang.reflect.Array.newInstance(String.class, 3);
String[] strArr = (String[])objArr;
I want to ask the rules java uses to do the casting. As far as I can tell the differences between the two examples is that, in the first one, objArr is an Object array with component of type Object. the second is an Object array with component of type String.
Please note that, I am not asking HOW to do the conversion, don't show me how to do this using Arrays.copyOf or other libraries.
Object[] objArr = {"a","b","c"};
String[] strArr = (String[])objArr;
With that the problem is {"a","b","c"}
which is an array of Object
s not String
s.
It's like doing something as follows -
Object obj = new Object();
String str = (String) obj; //ClassCastException
No exception with the following -
Object[] objArr = new String[] {"a","b","c"}; //Which is the case when you are using reflection
String[] strArr = (String[])objArr; //No exception
And it's like doing something as follows -
Object obj = new String();
String str = (String) obj;
"objArr" in first example is of type Object[]. "objArr" in second example is of type String[].
While String extends Object (String is a type of Object) String[] does not extend Object[] (a String-Array Object is not a type of Object-Array)
The fact that in the first example you put Strings into an Object[] (Object-Array) object doesn't make it a String[] (String-array):
Object[] objArr = {"a","b","c"};
System.out.println(objArr instanceof Object[]);//true
System.out.println(objArr instanceof String[]);//false
String[] objArr2 = {"a", "b", "c"};
System.out.println(objArr2 instanceof Object[]);//false
System.out.println(objArr2 instanceof String[]);//true
== On Covariance
It's not something that I grasp completly, but here's what I get from it:
In Java arrays are covariant, generics are not. Meaning that this works:
Object[] o = new String[3];
and this doesn't:
//ArrayList<Object> o = new ArrayList<String>(); //compile time error
also, this works:
function1(new String[2]);
static void function1(Object[] o) {
}
and this does not:
//function2(new ArrayList<String>()); //compile time error
static void function2(ArrayList<Object> o) {
}
There's a good reason why generics were restricted like that, but that's besides the point in this discussion.
However I believe that this is not really a discussion on covariance, but simply on how some classes are implemented in Java. An object of type String[] is also an object of type Object[] (with all the bad stuff that that brings), thus it is normal to be able to write:
Object[] o = new String[3];
however, BECAUSE of arrays' covariance, since you can treat a String[] as an Object[] and also in Object[] you can put whatever kind of types, you can specifically put Strings in an object array. I.E you can have this:
Object[] o = //whatever kind of array;
o[0] = //whatever kind of instance;
This however does not change the fact that o in the last example is of type Object[], therefore you cannot cast it to a String[].
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With