Sawyer
Sawyer

Reputation: 15927

Java array narrow casting rules

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.

Upvotes: 9

Views: 1174

Answers (3)

Shivan Dragon
Shivan Dragon

Reputation: 15229

"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[].

Upvotes: 1

Bhesh Gurung
Bhesh Gurung

Reputation: 51030

Object[] objArr = {"a","b","c"};
String[] strArr = (String[])objArr;

With that the problem is {"a","b","c"} which is an array of Objects not Strings.

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;

Upvotes: 7

Code-Apprentice
Code-Apprentice

Reputation: 83577

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.

Note that you are casting from an Object array reference to a String array reference. Thus narrowing doesn't apply because you are not casting the individual Object references to String references.

Upvotes: 0

Related Questions