如果
new ArrayList<?>(); // is not Legal
如果
new ArrayList<? extends Number>(); // is not Legal,
那为什么
new ArrayList<Set<?>>(); // IS Legal
有人可以举例解释。
答案 0 :(得分:2)
创建ArrayList时,必须为其泛型参数指定显式类型。 ?
或? extends Number
不是类型。 Set<?>
是一种类型(即Set,我们不关心其泛型类型)。
答案 1 :(得分: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
个可能包含任意类型对象的Set
。即您不关心Set
中的内容,但您确实关心ArrayList
您添加到ArrayList
。
因此,在新声明/创建的Set<?>
所执行的所有操作范围内Set
的部分可以自由转换为{{1}} :结果程序将具有等效的语义。
答案 2 :(得分:1)
这种情况会发生,因为在您的具体类型声明中,您使用interface作为泛型参数。想想将来如何使用它:
List someList = new ArrayList<Set<?>>();
Set<?> someSet = new HashSet<Integer>();
someList.add(someSet);
在第一行 - 您正在定义一个ArrayList
类型的列表,它将保留“某些设置”(任何类型)。然后,在第二行中,您将声明并定义具体类型HashSet
的集合。它被转换为Set<?>
,因此将它添加到以前创建的列表中没有问题。
答案 3 :(得分:0)
那是因为 unknown ?
无法转换为任何类型。
new ArrayList<?>();
将导致以下结果(假设可以编译)。
List<?> list = new ArrayList<?>();
list.add(? e); //Java sees this as WTF???
由于此?
未知,因此java将其转换为list.add(null e);
,这是错误的。
答案 4 :(得分:0)
new ArrayList<?>()
不会很有用。考虑通配符的含义是有帮助的:
? extends Foo
表示您无法放入任何内容(null
除外),但您可以将对象视为Foo
? super Foo
表示您可以放入Foo
,但无法取出对象(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;
}