如何在java中创建一个类型安全的通用数组?

我想在java中创建一个通用数组,保持Java通常提供的类型安全性。

我正在使用此代码:

class Stack { private T[] array = null; public Stack(Class tClass, int size) { maximumSize = size; // type unsafe //array = (T[])new Object[maximumSize]; this.array = (T[])java.lang.reflect.Array.newInstance(tClass,maximumSize); } 

这个代码类型安全吗? 如果是这样,为什么? 为什么如果它是类型安全我需要演员?

Array.newInstance(..)方法的返回类型为Object 。 因此,您无法直接将其分配给除Object之外的任何内容。 因此你需要一个演员。

该方法委托给一个native方法

创建具有指定组件类型和长度的新数组

因此它创建了一个T类型的数组。

类型安全,假设array声明为

 T[] array; 

,由Class参数和使用相同类型变量的强制转换保证。

你应该添加

 @SuppressWarnings("unchecked") 

在您的源代码中解释上述原因的评论。 总是评论为什么一个警告你压制的演员是安全的。

由于原始的Class对象,它不是类型安全的。 例如,我可以通过以下方式创建一个新的Stack:

 new Stack(boolean.class, 10); 

编译器可以,但抛出exception,因为boolean.class是一个Classboolean[]不能转换为Boolean[]

您展示的替代方案已注释掉:

 array = (T[])new Object[size]; 

实际上有点类型安全但出于不同的原因:它是由于擦除。 例如,您不能将new Object[size]转换为Number[] ,但转换不会在数组上发生。 它会在一段时间后发生,就像从方法中返回数组元素一样(在这种情况下,元素被转换)。 如果您尝试执行某些操作(例如将数组返回到对象外部),则会引发exception。

通常,解决方案不是一般地键入数组。 相反,做这样的事情:

 class Stack { 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 tClass, int size) { if(tClass.isPrimitive()) throw new IllegalArgumentException(); // ... } 

由于Array.newInstance返回一个Object因此需要Array.newInstance 。 在这种情况下,编译器将始终发出警告。 这是generics的限制。

我们知道在编译时检查generics,我的朋友java.lang.reflect.Array.newInstance(tClass,size); 返回对象并输入类型,如果数组不是T []类型,则可能存在编译时错误