我想在java中创建一个通用数组,保持Java通常提供的类型安全性。
我正在使用此代码:
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);
}
此代码类型是否安全?如果是这样,为什么?为什么如果它是类型安全我需要演员?
答案 0 :(得分:9)
Array.newInstance(..)
方法的返回类型为Object
。因此,您无法直接将其分配给Object
以外的任何其他内容。因此你需要一个演员。
该方法委托给native
方法
创建具有指定组件类型和长度的新数组
因此,它正在创建一个T
类型的数组。
类型安全,假设array
被声明为
T[] array;
,由Class<T>
参数和使用相同类型变量的强制转换保证。
您应该添加
@SuppressWarnings("unchecked")
在您的源代码中解释上述原因的评论。总是评论为什么你正在压制警告的演员是安全的。
答案 1 :(得分:2)
由于原始的Class对象,它不是类型安全的。例如,我可以通过以下方式创建一个新的堆栈:
new Stack<Boolean>(boolean.class, 10);
编译器可以,但会抛出异常,因为boolean.class
是Class<Boolean>
而boolean[]
无法转换为Boolean[]
。
您展示的替代方案已注释掉:
array = (T[])new Object[size];
实际上有点类型安全,但出于不同的原因:它是由于擦除。例如,您不能将new Object[size]
强制转换为Number[]
,但是阵营中永远不会发生转换。它会在一段时间后发生,就像从方法中返回数组元素一样(在这种情况下元素被转换)。如果您尝试执行某些操作(例如将数组返回到对象外部),则会引发异常。
通常解决方案不是一般地键入数组。相反,做这样的事情:
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;
}
}
以上演员类型是安全的,因为您只能将E
推入数组。 JDK Stack(扩展Vector)和ArrayList都以这种方式工作。
如果你想使用newInstance
,你必须拒绝原语,因为无法一般地表示它们:
Stack(Class<T> tClass, int size) {
if(tClass.isPrimitive())
throw new IllegalArgumentException();
// ...
}
答案 2 :(得分:1)
由于Array.newInstance
返回Object
,因此需要进行投射。在这种情况下,编译器将始终发出警告。这是泛型的限制。
答案 3 :(得分:0)
我们知道在编译时检查泛型,我的朋友 java.lang.reflect.Array.newInstance(tClass,大小);返回对象并输入类型,如果数组不是T []类型,则可能存在编译时错误