Java 如何正确使用泛型类型的数组?

Java 如何正确使用泛型类型的数组?,java,generics,Java,Generics,我有一个类,它根据消息的类将传入消息映射到匹配的读取器。所有消息类型都实现接口消息。读取器在mapper类中注册,说明它将能够处理哪些消息类型。这些信息需要以某种方式存储在消息读取器中,我的方法是从构造函数中设置一个私有final数组 现在,我似乎对泛型和/或数组有一些误解,我似乎无法理解,请参阅下面的代码。这是什么 public class HttpGetMessageReader implements IMessageReader { // gives a warning becau

我有一个类,它根据消息的类将传入消息映射到匹配的读取器。所有消息类型都实现接口消息。读取器在mapper类中注册,说明它将能够处理哪些消息类型。这些信息需要以某种方式存储在消息读取器中,我的方法是从构造函数中设置一个
私有final
数组

现在,我似乎对泛型和/或数组有一些误解,我似乎无法理解,请参阅下面的代码。这是什么

public class HttpGetMessageReader implements IMessageReader {
    // gives a warning because the type parameter is missing
    // also, I actually want to be more restrictive than that
    // 
    // private final Class[] _rgAccepted;

    // works here, but see below
    private final Class<? extends IMessage>[] _rgAccepted;

    public HttpGetMessageReader()
    {
        // works here, but see above
        // this._rgAccepted = new Class[1];

        // gives the error "Can't create a generic array of Class<? extends IMessage>"
        this._rgAccepted = new Class<? extends IMessage>[1];

        this._rgAccepted[0] = HttpGetMessage.class;
    }
}
公共类HttpGetMessageReader实现IMessageReader{
//由于缺少类型参数,因此发出警告
//而且,我实际上想比这更严格一些
// 
//私人最终课程[]接受;
//在这里工作,但请参见下文
Java不允许私有final类。有关详细信息,请参阅

要回答您的问题,只需使用(可能)而不是数组

更多解释请参见:

泛型不是协变的 虽然你可能会发现 将收藏视为一种艺术 对于数组的抽象,它们有一些 集合所具有的特殊属性 不是。Java语言中的数组是 协变的,也就是说如果 整数扩展了它所指定的数字 则不仅是一个
整数
也是一个数字,但不允许使用
整数[]
还有一个
号码[]
,您可以 传递或分配一个
整数[]
,其中 调用编号[]
。(更多信息) 形式上,如果
Number
是超类型 如果是
整数
,则
数字[]
是一个
整数[]
的超类型 我认为泛型也是如此 还有类型--
列表
列表的超类型,并且
您可以传递一个
列表
其中需要一个
列表
。 不幸的是,这不起作用 对

事实证明这是一个很好的理由 这样不行:它会坏的 假设类型安全泛型 提供。想象一下你可以分配一个
列表
列表
。 那么下面的代码将允许 你想把一些不是
整数
放入
列表

List li=new ArrayList();
列表ln=li;//非法
增加(新浮动(3.1415));
因为ln是一个
列表
,添加 一个
浮点数
对它来说似乎是完全合法的。 但是如果ln的别名是li那么 这将违反类型安全承诺 隐含在李的定义中-- 这是一个整数列表 这就是泛型类型不能被定义的原因 协变的


数组总是属于特定的类型,这与泛型之前的集合不同

而不是

Class<? extends IMessage>[] _rgAccepted;
泛型不包括在内

那么什么是“正确的”(或者至少是普通的)方法呢

@SuppressWarnings(value=“unchecked”)
公共T[]的(类componentType,整型大小){
return(T[])Array.newInstance(componentType,size);
}
公共演示(){
整数[]a=of(Integer.class,10);
System.out.println(Arrays.toString(a));
}

克莱特斯说的没错。泛型类型参数的通常强制不变性与Java数组的协变性之间存在普遍的不匹配

(一些背景:Variance指定类型在子类型方面如何相互关联。例如,由于泛型类型参数是不变的 收集IMHO


this.\u rgAccepted=(类这两行实际上并不相等。我确实希望传递类对象。然后,正如cletus所建议的,您将希望使用ArrayList(或另一个集合对象)而不是数组。类不是泛型类型,它是表示类元数据的类。(这让我想起了我曾经读过的一句话:“每个类对象的对象都有一个表示对象类的类对象”)类是泛型类型。更具体地说,它有一个类型参数,即它实际上被称为类。请看FAQ链接非常有用,谢谢。具有讽刺意味的是,根据我发现的一些文章,像ArrayList这样的集合似乎在幕后使用未经检查的类型转换,所以我可以只执行@SuppressWarnings(“未经检查”)我自己。是的,这是完全合理的。我试着对@SuppressWarnings的每一次使用进行评论,以便我以后理解其背后的原因。顺便说一句:仅出于编译时原因使用集合类型,在您可能确实需要运行时数组语义的情况下,似乎不是我的一般答案……在许多情况下,必须找到一个平衡静态类型安全性和性能运行时行为之间的差异(即使ArrayList相对于普通数组的成本很小),如果您不介意以Object[]而不是(可能是泛型的)组件类型的原始类型结束,请将新对象[size]强制转换为t[]将更快。Array.newInstance必须支付通常的反射成本。您不能分配对象[size]数组,然后将其用作T[].Array。newInstance(Foo.class,N)类似于malloc(sizeof(struct Foo)*N。return(T[])新对象[size];不能分配给整数[]它是一个java.lang.ClassCastException
Class<? extends IMessage>[] _rgAccepted;
IMessage[] _rgAccepted;
@SuppressWarnings(value="unchecked")
public <T> T[] of(Class<T> componentType, int size) {
    return (T[]) Array.newInstance(componentType, size);
}

public demo() {
    Integer[] a = of(Integer.class, 10);
    System.out.println(Arrays.toString(a));
}
public static <T> T[] array(T...els){
    return els;
}
void test(){
    // warning here: Type safety : A generic array of Class is created for a varargs parameter
    Class<? extends CharSequence>[] classes = array(String.class,CharSequence.class);
}
this._rgAccepted = (Class<? extends IMessage>[])new Class[1];