显式指定通配符的上限时是否有区别?
假设我有一个通用的.class Generic<A extends BaseType>
就 Java 语言规范而言,以下两种类型声明之间是否存在显著差异?
Generic<?>
Generic<? extends BaseType>
嵌套通配符呢?
List<Generic<?>>
List<Generic<? extends BaseType>>
考虑到这一点,我认为这些是等效的。 指定类型参数具有上限。Generic
A
BaseType
因此,通配符应始终由 “自动” 或 “隐式” 限定,无论我是否显式指定它。BaseType
下面,我试图将我的直觉与JLS相协调。
我找不到有关“隐式”边界的信息,因此我首先查看了子类型规则。
阅读有关子类型$ 4.10.2的JLS部分,它说:
给定一个泛型类型声明 (n > 0),参数化类型的直接超类型 ,其中 Ti (1 ≤ i ≤ n) 是一个类型,它们都如下:
C<F1,...,Fn>
C<T1,...,Tn>
D<U1 θ,...,Uk θ>
,其中 是泛型类型,它是泛型类型的直接超类型,θ 是替换 [F1:=T1,...,Fn:=Tn]。D<U1,...,Uk>
C<T1,...,Tn>
C<S1,...,Sn>
,其中 Si 包含 Ti (1 ≤ i ≤ n) (§4.5.1)。
(强调我的)
据我所知,“通配符”在JLS中不被视为“类型”。所以这不能适用于前两个例子,但它适用于这两个例子。List
相反,这应该适用:
给定泛型类型声明 (n > 0),参数化类型的直接超类型(其中至少一个 Ri (1 ≤ i ≤ n) 是通配符类型参数,是参数化类型的直接超类型,它是将捕获转换为 (§5.1.10) 的结果。
C<F1,...,Fn>
C<R1,...,Rn>
C<X1,...,Xn>
C<R1,...,Rn>
(强调我的)
将捕获转换 $5.1.10 应用于 和 ;我想我在新鲜类型变量上得到了相同的界限。捕获转换后,我可以使用“包含”规则来建立子类型。Generic<?>
Generic<? extends BaseType>
对于第一个示例,通过
如果 Ti 是形式为 ?的通配符类型参数 (§4.5.1),则 Si 是一个新类型变量,其上限为 Ui[A1:=S1,...,An:=Sn],下限为空类型 (§4.1)。
因为 A1 是 ,所以 fresh 变量的上限为 。BaseType
BaseType
对于第二种情况,通过
如果 Ti 是以下形式的通配符类型参数?扩展 Bi,则 Si 是一个新类型变量,其上限为 glb(Bi, Ui[A1:=S1,...,An:=Sn]),下限为空类型。
glb(V1,...,Vm) 被定义为 V1 & ...& Vm.
我得到,这又是.glb(BaseType, BaseType)
BaseType
因此,根据JLS,和之间的子类型关系似乎是双向的,这与我的直觉相匹配。Generic<?>
Generic<? extends BaseType>
对于嵌套通配符,我将使用“包含”规则:
如果 T2 表示的类型集可证明是 T1 在以下规则的自反和传递闭包下表示的类型集的子集(其中<:表示子类型 (§4.10)),则类型参数 T1 称为包含另一个类型参数 T2,编写为 T2 <= T1:
? extends T <= ? extends S if T <: S
? extends T <= ?
? super T <= ? super S if S <: T
? super T <= ?
? super T <= ? extends Object
T <= T
T <= ? extends T
T <= ? super T
结合
C<S1,...,Sn>, where Si contains Ti (1 ≤ i ≤ n) (§4.5.1).
从上面,我得到:
List<Generic<?>>
是 if 包含的直接超类型List<Generic<? extends BaseType>>
Generic<?>
Generic<? extends BaseType>>
虽然,我不明白我如何使用包含规则。根据规则,我唯一可以使用的其他信息是子类型。我已经知道子类型在两种类型之间是双向的。
虽然,如果两者之间包含子类型是答案,我也可以证明这是一个子类型,它不是也不应该是。List<String>
List<Object>
此外,我需要显示一些形式,并且具有表单“类型”右侧的唯一规则是 ,因此这些规则似乎根本没有帮助。Type <= OtherType
T <= T
我如何通过JLS获得它并且是彼此的子类型?List<Generic<?>>
List<Generic<? extends BaseType>>