如何在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
是一个Class
而boolean[]
不能转换为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 []类型,则可能存在编译时错误