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

Han*_*etz 19 java generics

我有一个类根据消息的类将传入的消息映射到匹配的阅读器.所有消息类型都实现接口消息.读者在mapper类中注册,说明它将能够处理哪些消息类型.这些信息需要以某种方式存储在消息阅读器中,我的方法是private 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

ETA: 正如cletus正确指出的那样,最基本的Google搜索显示Java不允许通用数组.对于给出的示例我肯定理解这一点(比如E[] arr = new E[8],哪里E是周围类的类型参数).但为什么new Class[n]允许?那么"适当的"(或者至少是常见的)方式是什么呢?

cle*_*tus 30

Java不允许通用数组.Java Generics FAQ中的更多信息.

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

Java理论和实践中可以找到更多解释:泛型陷阱:

泛型不是协变的

虽然您可能会发现将集合视为数组的抽象是有帮助的,但它们具有集合不具有的一些特殊属性.Java语言中的数组是协变的 - 这意味着如果Integer扩展Number(它确实如此),那么不仅是Integer 一个数字,而且Integer[]也是一个Number[],你可以自由地传递或分配Integer[]一个 Number[]被调用的地方对于.(更正式,如果Number是的超类型Integer,则Number[]是一个超类型Integer[].)你可能会认为同样是泛型类型也是如此-这List<Number> 是一个超List<Integer>,并且您可以通过一个List<Integer> 其中List<Number>的预期.不幸的是,它没有那种方式.

事实证明它有一个很好的理由它不会那样工作:它会破坏应该提供的类型安全仿制药.想象一下,你可以指定 List<Integer>一个List<Number>.然后,下面的代码将允许您将不属于的内容 Integer放入List<Integer>:

List<Integer> li = new ArrayList<Integer>();
List<Number> ln = li; // illegal
ln.add(new Float(3.1415));
Run Code Online (Sandbox Code Playgroud)

因为ln是a List<Number>,添加Float它似乎是完全合法的.但是如果ln与li混淆,那么它将破坏li定义中隐含的类型安全承诺 - 它是一个整数列表,这就是泛型类型不能协变的原因.