2011-12-30 108 views
2

我正在为SCJP/OCPJP学习,并且遇到了一个接近我的奇怪问题。实例化类型的泛型类<?>

示例代码实例化两个通用的集合:

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

的“正确”答案的问题是,这个代码将编译,但加入要么集合将产生一个运行时错误。

当我尝试编译这样的代码时,我只是得到错误。 Java教程甚至没有显示这种类型的代码,它通常使用通配符作为upcast的一部分。

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

上面即使是合法的代码,这两个泛型集合?第二个由我的逻辑只会禁止接口。第一个看起来完全没用。为什么要使用一种通用的方法来控制?

+0

看不到这会编译和你可以添加到两个集合就好 - 只是只有一个对象。我把它作为练习让读者弄清楚每个班级哪个对象是有效的:) – Voo 2011-12-30 19:26:56

+0

你也不能这样做。我想知道问题/答案是否是错误的,而且显然是这样。 – jeremyjjbrown 2011-12-30 20:18:25

+0

刚刚投票因为什么原因? – jeremyjjbrown 2014-03-01 18:52:26

回答

4

退房出色Java generics tutorial PDF。更具体地说有关通配符的部分包含回答你的问题,我引用

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

因为我们不知道是什么的c代表元素类型,我们不能 对象添加到它。 add()方法采用类型为E的参数,集合的元素类型为 。当实际类型参数是?, 它代表某种未知类型。我们通过添加的任何参数 都必须是此未知类型的子类型。由于我们不知道什么样的 类型,我们不能通过任何东西。唯一的例外是null, 这是每种类型的成员。

+0

该文件确实非常有用。谢谢!你是否知道任何反射或内心阶层都很好的文章? – jeremyjjbrown 2011-12-31 03:44:47

1

我在this的答案中回答了这个问题。 ?不能用于实例化。我不确定它为什么说代码会编译,我用过的任何java编译器都不允许这样做。你可以做什么是由以下如上图所示:

List<?> list = new ArrayList(); 

这将编译和运行,但你不能这样做:

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

如果要声明在运行时类型,你可以做这样的事情:

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

} 
0

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