考虑以下几个类:
class A{ }
class B extends A{ }
我们知道编译好了:
List<? extends A> xx = new ArrayList<B>();
List<? extends List<? extends A>> xy = new ArrayList<List<? extends A>>();
但这会产生编译时错误
List<? extends A> yx = new ArrayList<? extends A>();
List<? extends List<? extends A>> yy = new ArrayList<? extends List<? extends A>>();
错误说:
必需:没有边界的类或接口
我知道编译器为上述初始化解释的新值是不同的,因此无法安全地转换它们。 但是,没有界限的是什么?在上面的错误消息中意味着什么?
答案 0 :(得分:4)
此错误指的是创建新的ArrayList
,其直接顶级类型参数使用通配符。尽管允许嵌套类型参数具有通配符,但这是不允许的。
JLS, Section 15.9, "Class Instance Creation Expressions",声明:
如果 TypeArguments 紧接在
new
之后,或紧接在(
之前,那么如果任何类型参数是通配符({{},则它是编译时错误3}})。
这里的关键词是&#34;立即&#34;,因为它代表直接类型参数,而不是嵌套类型参数。
以下是§4.5.1中提到的限制:
它们[通配符]不能用于创建对象或数组,也就是说,新表达式中不允许使用通配符实例化。通配符实例化不是类型,它们是来自类型族的成员的占位符。在某种程度上,通配符实例化类似于接口:我们可以声明接口类型的变量,但是我们不能创建接口类型的对象;创建的对象必须是实现接口的类类型。与通配符实例化类似:我们可以声明通配符实例化类型的变量,但是我们不能创建这种类型的对象;创建的对象必须是通配符实例化指定的实例化系列的具体实例。
(强调我的)
基本上,通配符类型不是具体类型,无法实例化,类似的原因是不允许直接创建接口实例。
但是,这并未说明嵌套通配符,这些通配符与最初不相关的对象的创建有关,这些对象最终可能与此类型相关联。在您的示例中,这将是可以添加到外部List
的嵌套ArrayList
。它们可能是对任何匹配通配符类型的List
的引用,但它们并未在此处创建。
<强>摘要强>
Java不允许在实例创建表达式中使用通配符(使用new
),但它允许在这样的表达式中使用嵌套通配符,因为直接通配符类型不是具体类型。 / p>
答案 1 :(得分:2)
正在创建的类实例的类型参数不能是通配符(§15.9):
如果在[{1}}之后或紧接在
new
之前存在[类型参数],那么如果任何类型参数是通配符,则它是编译时错误。
这就是它。类型参数可能包含通配符(如(
中所示),但不能直接给出通配符(如new ArrayList<List<?>>
中所示)。
上述引用引用的类型参数的语法(§4.5.1)可能会澄清这种区别:
new ArrayList<?>
换句话说,对于提供给类实例创建表达式的TypeArguments:
< TypeArgumentList >
TypeArgumentList:
TypeArgument {, TypeArgument}
TypeArgument:
ReferenceType
Wildcard
Wildcard:
{Annotation} ? [WildcardBounds]
WildcardBounds:
extends ReferenceType
super ReferenceType
中的每个TypeArgument
,TypeArgumentList
可能只是TypeArgument
而不是{{1} }}。如果引用类型本身泛型,那么可以具有提供给 it 的类型参数,这些参数是通配符。
答案 2 :(得分:0)
在构造/防御泛型类型时,必须指定类型。这两个
? extends A
? extends List<? exetnds A>
正在创建一个新的通配符,这是一种未知的泛型类型(你可以从前面的?中看出来。)
这两个
B
List<? extends A>
是实际类型。所以在打电话时
new ArrayList<B>();
new ArrayList<List<? extends A>>();
指定了泛型类型。在一次案例中,它是B
,在另一种情况下,它是包含List
的{{1}}。
致电
new ArrayList(); 新的ArrayList&gt;();
两次都没有定义泛型类型。这是不允许的。
? extends A
不会导致错误的原因是,因为这是一种类型。原始List<? extends A>
中的列表尚未创建。您只能在以后定义它必须是List<? extends List<? extends A>>
。如果您尝试像这样创建此列表
List<? extends A>
你会遇到同样的问题。
可理解?