Copying Generic Arrays in Java
Intro
Copying an array.
It sounds so simple - run a quick for
loop,
or better yet, System.arraycopy
.
System.;
What if you need to perform a destructive operation? [1]
In my Data Structures class, we're asked to implement heap sort
without modifying the original array.
This is simple enough: use array.clone
.
It preserves the order of the original array while giving you a new instance.
T[] tmp ;
Remember that this is a destructive operation, however; you need a new third array in which to store the result. Only one problem: Java doesn't allow generic arrays to be created. Trying to do so is a compile-time error:
;
)
Fine, let's do some ugly casting.
T[] array = (T[]) new Object[0];
Strange happenings
So far, this has all been pretty standard. Java has type erasure, Java generics are a pain, yadda yadda. Now we get to the strange part of this post.
; ;
)
What?!‽
Not only are we getting a ClassCastException
trying to convert Integer
to Integer
,
but we're getting it at runtime, not compile-time!
Worse yet, there's no traceback - the error pointed to main
, not to getNew
!
My solution
What happens when you declare a new array in Java?
You might assume that this is translated directly to Java bytecode, but you would be incorrect.
javac
actually translates this to java.lang.reflect.Array.newInstance
, which in turn
calls
the native method java.lang.reflect.Array.newArray
.
In fact, you can call this method yourself, but only if you have the class type.
Type parameters don't cut it.
Well, if you have an instance of the class, you can call instance.getClass()
.
If you don't, you can (in this particular case) return a null pointer,
since the array must be empty.
% cat copy.java
;
Conclusion
I still have no idea what's going on here - my best guess is that due to type erasure,
the JIT compiler doesn't know that the objects in
array
are actually valid Integer
s.