2012-01-05 46 views

回答

1

发生这种情况是因为在您的具体类型声明中,您将接口用作泛型参数。想想如何在将来使用:

List someList = new ArrayList<Set<?>>();  
Set<?> someSet = new HashSet<Integer>(); 
someList.add(someSet); 

在第一线 - 你定义ArrayList类型的列表,将举行“一些集”(任何类型)。然后,在第二行中,您声明并定义了一组具体类型HashSet。它被铸造成Set<?>,所以将它添加到先前创建的列表中没有问题。

2

创建ArrayList时,您必须为其泛型参数指定显式类型。 ?? extends Number不是类型。 Set<?>是一种类型(即Set,我们不关心它的泛型类型)。

0

这是因为未知?无法翻译成任何类型。

new ArrayList<?>(); 

将导致以下情况(假设可以编译)。

List<?> list = new ArrayList<?>(); 
list.add(? e); //Java sees this as WTF??? 

由于这?是未知的,Java的转换这list.add(null e);,这是errornous。

+0

如果这是真的,'名单名单=新的ArrayList ()'也应该是非法的,但事实并非如此。 – yshavit 2012-01-05 08:30:23

+0

@yshavit,我没有指定'ArrayList ()',但'ArrayList ()',你指定的是另一种不同的情况。 – 2012-01-05 09:06:21

+0

我明白了,但如果你用'List list = new ArrayList ()'替换你的行'列表 list = new ArrayList ()',你的第二行将完全不变。所以这并不能解释为什么'new ArrayList ()'不被允许。 – yshavit 2012-01-05 09:12:00

1

的答案已经给出了,所以这里就是你需要做的什么,而不是

ArrayList example1 = new ArrayList(); // any object will do. 
ArrayList<Object> example2 = new ArrayList<Object>(); // since everything inherits from Object anyway... 

的,如果你不关心的事情的清单中包含的类型是什么第一

然后,如果你想添加任意Number对象是什么:

ArrayList<Number> example3 = new ArrayList<Number>(); // any Number may be added 

最后,以前的答案格罗斯你的最后一个例子的意义。

ArrayList<Set<?>> example4 = new ArrayList<Set<?>>(); 

这一个意味着你构建你希望找到一个ArrayList /放Set S的可以包含任意类型的对象。即你不在乎Set中的内容,但是你确实在乎它是Set是你添加到你的ArrayList

结果,你的新声明的执行的所有操作的范围内/创建ArrayListSet<?>的部分可以自由地转换为Set:结果程序将有相当的语义。

0

new ArrayList<?>()不会很有用。这是有帮助的想想通配符的意思是:

  • ? extends Foo意味着你不能把任何东西(除了null),但你可以得到的物品运为Foo
  • ? super Foo意味着你可以把Foo S IN,但你不能让物体出(除Object
  • ?是交集:你不能把任何东西(除了null),并且你不能出去的对象(除Object

请注意,List<Foo>可以投射到List<? extends Foo>,List<? super Foo>List<?>,但这三者中的任何一个都不能安全投射到List<Foo>

因此,假设您创建了new ArrayList<?>()。你可以给它分配什么样的参考?只有一个List<?>。这意味着你将无法将任何引用放入(除null之外),并且除了Object之外,您将无法获取任何引用。换句话说,这个泛型比泛型替代的原始类型略有用处。

当您看到List<?>List<? extends Foo>时,很有可能有人将其创建为非通配类型,然后将其转换为通配类型。例如:

List<? extends Number> getSomeNumbers() { 
    List<Number> numbers = new ArrayList<Number>(); 
    numbers.add(1); 
    numbers.add(2L); 
    numbers.add(3.14); 
    return numbers; // implicit casting to List<? extends Number> 
} 

在这个例子中,如果numbers一直类型为List<? extends Number>,没有add行会编译,所以它不会是有益的。如果我们将对象构建为new ArrayList<? extends Number>(),我们别无选择,只能以无用的通配形式引用它。

同样,如果您创建了new ArrayList<? super Number>(),那么这些添加就可以工作,但是您应该保证没有人能够检索到值,除非是Object。你可以通过创建(和引用)new ArrayList<Object>()来做同样的事情。

那么,为什么new ArrayList<Set<?>>()允许?因为它有用;我们可以添加元素到列表中,以及检索它们。当我们创建每个集合时,我们将创建它,而不使用通配符,以便我们可以添加它,然后我们将它放下并添加到列表中。

List<Set<?>> getSomeSets() { 
    List<Set<?>> list = new ArrayList<Set<?>>(); 
    Set<Number> set = new HashSet<Number>(); 
    set.add(1); 
    set.add(2L); 
    set.add(3.14); 
    Set<?> wildcardSet = set; // allowed, though not actually needed 
    list.add(wildcardSet); 
    list.add(set); // don't need to go through intermediate wildcardSet 
    return list; 
} 
相关问题