I want to create a generic array in java maintaining the type safety usually offered by Java.
I am using this code :
class Stack<T> {
private T[] array = null;
public Stack(Class<T> tClass, int size) {
maximumSize = size;
// type unsafe
//array = (T[])new Object[maximumSize];
this.array = (T[])java.lang.reflect.Array.newInstance(tClass,maximumSize);
}
is this code type safe? ans if so, why? why if it is type safe I need a cast?
The Array.newInstance(..)
method has a return type of Object
. As such, you cannot directly assign it to anything other than Object
. You therefore need a cast.
The method delegates to a native
method which
Creates a new array with the specified component type and length
Therefore it is creating an array of type T
.
The type safety, assuming array
is declared as
T[] array;
, is guaranteed by the Class<T>
parameter and the cast using the same type variable.
You should add the
@SuppressWarnings("unchecked")
with a comment explaining the above reason in your source code. Always comment why a cast whose warning you are suppressing is safe.
It's not type safe because of the primitive Class objects. For example I can create a new Stack in the following manner:
new Stack<Boolean>(boolean.class, 10);
Which is OK with the compiler but throws an exception because boolean.class
is a Class<Boolean>
and boolean[]
cannot be cast to Boolean[]
.
The alternative you show commented out:
array = (T[])new Object[size];
Is actually somewhat type safe but for a different reason: it is due to erasure. You cannot, for example, cast a new Object[size]
to a Number[]
, but the cast never happens on the array. It happens some time later, like when you return an element of the array from a method (in which case the element is casted). If you tried to do something like return the array to outside the object it will throw an exception.
Usually the solution is not to generically type the array. Instead, do something like this:
class Stack<E> {
Object[] array = new Object[10];
int top;
void push(E elem) {
if(top == array.length)
array = Arrays.copyOf(array, array.length * 2);
array[top++] = elem;
}
E pop() {
@SuppressWarnings("unchecked")
E elem = (E)array[--top]; // type safe cast
array[top] = null;
return elem;
}
}
The above cast is type safe because you can only push an E
in to the array. Both the JDK Stack (which extends Vector) and ArrayList work this way.
If you want to use newInstance
, you would have to reject primitives as there is no way to represent them generically:
Stack(Class<T> tClass, int size) {
if(tClass.isPrimitive())
throw new IllegalArgumentException();
// ...
}
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