Java泛型类型中的通配符参数在其范围内的正式条件是什么?

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通配符:Foo无效。这是有意义的,因为没有类型可以同时是NumberThread的子类型。
  • ? super通配符中,通配符中的下界必须是类型变量绑定的子类型:不允许Foo,因为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=Foo:即c=Foo,n=1,t1=? super Runnable,b1=Number

    对于捕获转换,此部分捕获转换定义适用:

    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=Foo,其中X是一个具有上界Number和下界Runnable的新类型变量。我没有看到任何明确禁止使用这种类型变量的内容。

    b1=Number中没有类型变量,所以bi[a1:=x1,…,an:=xn]仍然只是Number而已。X使用Number作为上界(来自捕获转换),根据子类型规则"类型变量的直接超类型是其界中列出的类型",因此X小于:Number(=bi[a1:=x1,…,an:=xn]),因此该参数在其界内。(但事实并非如此!)

    按照相同的推理,每个通配符都在其边界内,因此这里的某些内容不正确…但这种推理到底哪里出错了呢?这些规则在正确应用时如何工作?


    关于泛型的jls是不完整的,您在其中发现了另一个漏洞。关于类型变量的下界几乎没有讨论过,我在规范中也没有看到对具有上界Number和下界RunnableX的任何限制。他们可能忘了。

    直观地说,必须至少有一个可能的类型同时满足类型变量的上界和下界,否则该变量和所有使用该变量的类型都将是无用的。因为这几乎肯定是一个编程错误,所以编译应该失败。

    很容易检查上界和下界是否构成空的类型集。所有下界的超类型都是已知的;它们中至少有一个应该是上界,否则两个边界内没有类型。

    ——

    两个Foo案例在规范中有很好的定义,通过捕获转换,我们有了新的类型变量X和上界A & Number,规范中说是上界V1&...&Vm

    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=线程,则捕获转换失败。