如何使用通配符实例化generics?
让我们使用外卡研究一些通用的情况:
1
这段代码
List list = new ArrayList();
生成以下错误:
required: class or interface without bounds found: ?
2
但是这个
List list = new ArrayList< Set >();
汇编成功。
3
和这个:
List<Set> list = new ArrayList< Set >();
编译成功也是如此。
4
但是这个:
List<Set<Map>> list = new ArrayList< Set<Map> >();
生成
required: List<Set<Map>> found: ArrayList<Set<Map>>
五
List<Set> list = new ArrayList< HashSet >();
生成
required: List<Set> found: ArrayList<HashSet>
我对这些输出很困惑。
我看到以下规律性:
我可以替换?
从右侧部分的左侧部分仅在第一级,并且类型应该在内并且只是? 和? 是禁止的。
但我不明白为什么?
你能提供如何使用通配符实例化generics的通用规则吗?
- 您不能使用通配符直接实例化类型。 实例化时,type参数必须是实际类型,因此会生成编译器错误。
码:
List> list = new ArrayList>();
- 以下编译成功。
码:
List> list = new ArrayList< Set> >();
您可以使用通配符作为类型参数的generics类型参数,例如Set>
,一组任何东西。 此外,任何类型参数都将匹配通配符?
在左边。
- 这也成功编译:
码:
List> list = new ArrayList< Set> >();
类型参数匹配,和?
不直接用于上述(1)中。
- 以下内容无法编译:
码:
List>> list = new ArrayList< Set
这是因为即使Map
是Map, ?>
, List
也不是List
。 Javagenerics是不变的,这意味着类型参数必须匹配; 必须使用上限中的通配符明确指定“is-a”关系。 例如,通过在左侧引入上限通配符来编译此更改。
List extends Set extends Map,?>>> list = new ArrayList< Set
- 以下内容的编译原因与上述(4)相同:
码:
List> list = new ArrayList< HashSet> >();
即使HashSet>
是Set>
,由于Java的不变generics, ArrayList
不是List
。 在左边引入通配符作为上限也适用于此:
List extends Set>> list = new ArrayList< HashSet> >();
- 您无法使用通配符进行实例化。 您必须指定类型。 “?” 不是一种类型。
- 这没关系,因为你给
List>
一个类型,即Set>
。Set>
是一种类型。 - 正确。
ArrayList
是List
的子类型。 - 这是事情变得丑陋的地方。 右手不是左手的子类型,因为Java处理类型参数的方式很复杂。 类型参数必须完全匹配,或者您必须使用协方差/逆变(
或
stuff)。
List
不是List
的子类型。 它是List extends Object>
的子类型List extends Object>
List extends Object>
或只List>
。 - 与上面相同。 如果您已将其声明为
List extends Set>>
List extends Set>>
它会工作。