Friday, August 03, 2007

Lets discuss Array Typecasting

You would think this code should work:
Object[] objs = new Object[2];
objs[0]="Hello";
objs[1]="World";
String[] strs = (Str[]) Objs;
// print the array..

Code compiles fine, but when you run it, you get java.lang.ClassCastException. And you start wondering why? String is subclass of Object so its not narrow conversion then why do i get ClassCastException. I tried to find answer on net but could not find, so below is just my own logic (disclaimer :-) )

String extends Object fine, but String[] doesn't extend Object[] both of them extend Object, in short they are not in hierarchy so you get ClassCastException. Lets look into more detail

Lets try System.out.println(strs.getClass()); which prints --> [Ljava.lang.String
and System.out.println(obj.getClass()); prints --> [Ljava.lang.Object
only common thing is [L, what is this?

Class Type that defines an Object consist of two things ClassType and ComponentType. For all array objects class name is same i.e. [L, but component types differs. Which implies Java Arrays are special type of classes whoes Class Type is represented by [L. If you had some way of setting the componentType, typecast would have worked. But it is pretty obvious that setComponentType can't be exposed.

Now finally I think we should discuss the solution to above problem. There are two solutions but none which could avoid an additional array creation.

Solution 1:
String[] strs = new String[objs.length];
System.arraycopy(objs,0,strs,0, objs.length);

Solution 2:
If you are using List you can use Object[] List.toArray(Object[])
//assuming you have done List list = Arrays.asList(objs); for our current example.
String[] strs = new String[2];
strs = (String[])list.toArray(strs);

Now if you look at solution 2 and wonder why typecasting worked here, it worked because ComponentType of the Array returned by toArray method has ComponentType same as the componentType of the Array passed to it. The argument is just used to get the comonentType
i.e. this would also work
strs = (String[])list.toArray(new String[0]);

No comments: