【问题标题】:Instantiating a Generic Class of Type <?>实例化 <?> 类型的泛型类
【发布时间】:2011-12-30 19:20:24
【问题描述】:

我正在为 SCJP/OCPJP 学习,我遇到了一个对我来说很奇怪的示例问题。

示例代码实例化了两个泛型集合:

List<?> list = new ArrayList<?>();
List<? extends Object> list2 = new ArrayList<? extends Object>();

该问题的“正确”答案是该代码可以编译,但添加到任一集合都会产生运行时错误。

当我尝试编译这样的代码时,我会遇到错误。 Java 教程甚至没有显示这种类型的代码,而是通常使用通配符作为向上转换的一部分。

Collection<?> c = new ArrayList<String>();

上面的两个通用集合是合法的代码吗?按照我的逻辑,第二个只会禁止接口。第一个看起来完全没用。为什么要使用不尝试控制的泛型?

【问题讨论】:

  • 不知道这将如何编译,并且您可以很好地添加到两个集合中 - 只是恰好只有一个对象。我把它留给读者作为练习来确定哪个对象对每个类都有效:)
  • 你也做不到。我想知道示例问题/答案是否错误,显然是错误的。
  • 刚才因为什么原因投了反对票?

标签: java generics collections scjp ocpjp


【解决方案1】:

查看出色的Java generics tutorial PDF。更具体地说,关于通配符的部分包含您问题的答案,我引用了

Collection<?> c = new ArrayList<String>();
c.add( new Object() );

由于我们不知道c的元素类型代表什么,所以我们不能 向其中添加对象。 add() 方法接受 E 类型的参数,即 集合的元素类型。当实际类型参数为?时, 它代表某种未知类型。我们传递给 add 的任何参数都会 必须是这种未知类型的子类型。因为我们不知道什么 类型,也就是说,我们不能传递任何东西。唯一的例外是null, 它是每个类型的成员。

【讨论】:

  • 那个文件确实很有用。谢谢!你知道有哪些关于反射或内部类的文章吗?
【解决方案2】:

如果你想在运行时声明 Type,你可以这样做:

public class Clazz1<T> {

private final List<T> list = new ArrayList<T>();

private List<T> getList() {
    return list;
}

/**
 * @param args
 */
public static void main(String[] args) {
    Clazz1<Integer> clazzInt = new Clazz1<Integer>();
    clazzInt.getList().add(2);
    System.out.println(clazzInt.getList());

    Clazz1<String> clazzString = new Clazz1<String>();
    clazzString.getList().add("test");
    System.out.println(clazzString.getList());
}

}

【讨论】:

    【解决方案3】:

    我之前在this 回答中回答了这个问题。 ? 不能在实例化中使用。我不确定为什么它说代码可以编译,我使用的 java 编译器都不允许这样做。您可以通过以下方式执行上述操作:

    List<?> list = new ArrayList();
    

    这会编译并运行,但你不能这样做:

    list.add("hello world"); //This wouldn't compile
    

    【讨论】:

      【解决方案4】:

      new 生成对象的具体实例。具体实例只能有一种类型,包括任何泛型。知道这一点,通配符不能与new 一起使用。

      【讨论】:

        猜你喜欢
        • 2013-10-03
        • 2011-04-02
        • 2013-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多