首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何正确使用泛型类型的数组?

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

Stack Overflow用户
提问于 2009-05-22 10:32:00
回答 5查看 26.6K关注 0票数 21

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

现在,我似乎对泛型和/或数组有一些误解,我似乎无法弄清楚,请参见下面的代码。那是什么?

代码语言:javascript
复制
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;
    }
}

ETA:正如cletus正确指出的那样,最基本的谷歌搜索表明Java不允许泛型数组。对于给出的示例,我绝对理解这一点(比如E[] arr = new E[8]__,其中E是周围类的类型参数)。但是为什么允许使用new Class[n]呢?那么,做这件事的“适当”(或至少是常见)方式是什么呢?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2009-05-22 10:34:46

Java不允许使用generic arrays。有关更多信息,请参阅Java Generics FAQ

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

可以在Java theory and practice: Generics gotchas中找到更多解释

泛型不是协变的

虽然您可能会发现将集合视为数组的抽象很有帮助,但它们具有集合所没有的一些特殊属性。Java语言中的数组是协变的--这意味着如果Integer扩展了Number (确实如此),那么不仅Integer也是Number,而且Integer[]也是Number[],并且您可以自由地在调用Integer[]的地方传递或赋值Number[]。(更正式地说,如果NumberInteger的超类型,那么Number[]就是Integer[]的超类型。)您可能认为泛型类型也是如此-- List<Number>List<Integer>的超类型,您可以在需要List<Integer>的地方传递List<Number>。不幸的是,它不是这样工作的。

事实证明,它不能以这种方式工作有一个很好的理由:它会破坏泛型应该提供的类型安全。想象一下,您可以为List<Number>分配一个List<Integer>。然后,下面的代码将允许您将非Integer的内容放入List<Integer>中:

List li =新建ArrayList();List ln = li;//非法ln.add(new Float(3.1415));

因为ln是一个List<Number>,所以给它添加一个Float看起来完全合法。但是如果ln使用li作为别名,那么就会破坏li定义中隐含的类型安全承诺--它是一个整数列表,这就是为什么泛型类型不能协变的原因。

票数 32
EN

Stack Overflow用户

发布于 2009-05-22 11:05:02

cletus说的没错。泛型类型参数的通常强制不变性与Java数组的协方差之间通常存在不匹配。

(一些背景:方差指定了有关子类型的类型之间的关系。也就是说,由于泛型类型参数是不变的Collection <:Collection不成立。因此,对于Java类型系统,String集合不是CharSequence集合。数组是协变的,这意味着对于任何带有T<:U的T和U类型,T[] <:U[]。因此,可以将类型为T[]的变量保存到类型为U[]的变量中。由于自然需要其他形式的差异,因此Java至少允许将通配符用于这些目的。)

我经常使用的解决方案(实际上是hack )是声明一个生成数组的helper方法:

代码语言:javascript
复制
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);
}

由于擦除,生成的数组将始终是Object[]类型。

票数 4
EN

Stack Overflow用户

发布于 2009-05-22 11:02:55

,那么做这件事的“适当”(至少是常见的)方式是什么呢?

代码语言:javascript
复制
@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));
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/897251

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档