如何在java中创建类型安全的泛型数组?

如何在java中创建类型安全的泛型数组?,java,arrays,generics,Java,Arrays,Generics,我想在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中创建一个通用数组,以维护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);
}
类堆栈{
私有T[]数组=null;
公共堆栈(类tClass,int-size){
最大尺寸=尺寸;
//类型不安全
//数组=(T[])新对象[maximumSize];
this.array=(T[])java.lang.reflect.array.newInstance(tClass,maximumSize);
}
此代码类型安全吗?如果是,为什么?如果是类型安全的,为什么我需要强制转换?

该方法的返回类型为
Object
。因此,您不能直接将其分配给
Object
以外的任何对象。因此,您需要强制转换

该方法委托给一个
本机
方法,该方法

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

因此,它正在创建类型为
T
的数组

假设
数组
声明为

T[] array;
,由
参数和使用相同类型变量的强制转换保证

您应该添加

@SuppressWarnings("unchecked")

在源代码中用注释解释上述原因。请始终注释为什么禁止其警告的强制转换是安全的。

因为我们知道泛型是在编译时检查的,所以,我的朋友
newInstance(tClass,size);返回对象并进行类型转换,如果数组不是T[]然后可能会出现编译时错误,因为
数组。newInstance
返回一个
对象,它需要强制转换。在这种情况下,编译器将始终发出警告。这是泛型的限制。

由于基元类对象的原因,它不是类型安全的。例如,我可以通过以下方式创建一个新堆栈:

new Stack<Boolean>(boolean.class, 10);
实际上有点类型安全,但原因不同:这是由于擦除。例如,您不能将
新对象[size]
强制转换为
数字[]
,但强制转换从未在数组上发生。这种情况会在一段时间后发生,比如从方法返回数组的元素时(在这种情况下,该元素被强制转换)。如果尝试执行类似于将数组返回到对象外部的操作,它将引发异常

通常情况下,解决方案不是一般地键入数组。而是执行以下操作:

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;
    }
}

为什么我会收到未经检查的警告?您正在进行未经检查的强制转换,因此使用它会收到警告。@giuseppes,因为编译器不能保证它。方法规范应该是这样的。请注意,如果有专门用于引用类型数组的
newInstance
,编译器可以保证它。
static t[]newInstance(c类,int size)
注意,这样做会引发基元类型的异常。例如,
int.Class
是一个
,因此将
int[]
强制转换为
整数[]
。没有一种方法可以通用地表示基元。这就是它可能不安全的原因。在上面的代码中
(T[])
简单地强制转换到
对象[]
,因为类型T在编译时是未知的。因此
数组
必须是
对象[]类型
(或简单地
对象
)。如果返回类型为
T[]的值
然后,在调用时,当方法的返回值被赋值或使用时,编译器将向适当的类型抛出一个隐藏的强制转换。你能更新你的代码使其编译吗?T
来自哪里?数组如何声明?例如,你认为这是一个静态方法吗(这只是
Array#newInstance
的包装器)或者
Array
是字段,
T
是类的类型参数?非常详细的答案!
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;
    }
}
Stack(Class<T> tClass, int size) {
    if(tClass.isPrimitive())
        throw new IllegalArgumentException();

    // ...
}