由于原始的类对象,它并不是类型安全的。例如,我可以通过以下方式创建一个新的堆栈:
new Stack<Boolean>(boolean.class, 10);
编译器不会出错,但程序会抛出异常,因为
boolean.class
是一个
Class<Boolean>
,而
boolean[]
不能被强制转换为
Boolean[]
。
你展示的替代方法已经被注释掉了。
array = (T[])new Object[size]
实际上,Java某种程度上是类型安全的,但原因不同:这是由于擦除。例如,您不能将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];
array[top] = null;
return elem;
}
}
上面的代码是类型安全的,因为只能将 E
推入数组中。JDK Stack(它扩展了 Vector)和 ArrayList 都是这样工作的。
如果要使用 newInstance
,则必须拒绝原始类型,因为没有办法以通用方式表示它们:
Stack(Class<T> tClass, int size) {
if(tClass.isPrimitive())
throw new IllegalArgumentException();
}
(T[])
只是将其转换为Object[]
,因为类型T在编译时是未知的。因此,array
必须是Object[]
类型(或者简单地说是Object
)。如果您返回一个类型为T[]
的值,则在调用点处,当分配或使用方法的返回值时,编译器将抛出一个隐藏的转换到适当类型的转换。 - Hot LicksT
是从哪里来的?array
声明在哪里?例如,这是一个静态方法(它仅是Array#newInstance
的包装器),还是array
是一个字段,并且T
是类的类型参数? - Radiodef