What are the formal conditions for a wildcard parameter in a Java generic type to be within its bounds?
使用Java中的参数化类型,如何检查参数是否在其绑定工作中完全是通配符?
给一个这样的类:
1 | class Foo<T extends Number> {} |
通过测试编译器接受的内容,可以了解到:
- 允许使用不相关接口类型的
? extends 通配符:Foo extends Runnable> 有效 - 不允许使用不相关类类型的
? extends 通配符:Foo extends Thread> 无效。这是有意义的,因为没有类型可以同时是Number 和Thread 的子类型。 - 在
? super 通配符中,通配符中的下界必须是类型变量绑定的子类型:不允许Foo super Runnable> ,因为Runnable 不是Number 的子类型。同样,这种限制是完全合理的。
小精灵
但是这些规则是在哪里定义的呢?查看Java语言规范第4.5部分,我没有看到任何区别于类的接口,并且当应用我对JLS EDCOX1的解释时,7表示是有效的。所以我可能误解了一些事情。这是我的尝试:
从JLS的该部分:
A parameterized type consists of a class or interface name C and an actual type argument list
. It is a compile time error if C is not the name of a generic class or interface, or if the number of type arguments in the actual type argument list differs from the number of declared type parameters of C. In the following, whenever we speak of a class or interface type, we include the generic version as well, unless explicitly excluded. Throughout this section, let A1 , ... , An be the formal type parameters of C, and let be Bi be the declared bound of Ai. The notation [Ai := Ti] denotes substitution of the type variable Ai with the type Ti, for 1 <= i <= n, and is used throughout this specification. Let P = G
be a parameterized type. It must be the case that, after P is subjected to capture conversion (§5.1.10) resulting in the type G , for each actual type argument Xi, 1 <= i <= n , Xi <: Bi[A1 := X1, ..., An := Xn] (§4.10), or a compile time error occurs.
号
将其应用于p=
对于捕获转换,此部分捕获转换定义适用:
If Ti is a wildcard type argument of the form ? super Bi, then Si is a fresh type variable whose upper bound is Ui[A1 := S1, ..., An := Sn] and whose lower bound is Bi.
号
给出了g
b1=
按照相同的推理,每个通配符都在其边界内,因此这里的某些内容不正确…但这种推理到底哪里出错了呢?这些规则在正确应用时如何工作?
关于泛型的jls是不完整的,您在其中发现了另一个漏洞。关于类型变量的下界几乎没有讨论过,我在规范中也没有看到对具有上界
直观地说,必须至少有一个可能的类型同时满足类型变量的上界和下界,否则该变量和所有使用该变量的类型都将是无用的。因为这几乎肯定是一个编程错误,所以编译应该失败。
很容易检查上界和下界是否构成空的类型集。所有下界的超类型都是已知的;它们中至少有一个应该是上界,否则两个边界内没有类型。
——
两个
It is a compile-time error if for any two classes (not interfaces) Vi and Vj,Vi is not a subclass of Vj or vice versa.
号
因此,如果A=线程,则捕获转换失败。