Java泛型类型中的通配符参数在其范围内的正式条件是什么? [英] What are the formal conditions for a wildcard parameter in a Java generic type to be within its bounds?

查看:93
本文介绍了Java泛型类型中的通配符参数在其范围内的正式条件是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Java中的参数化类型时,如何检查参数是否处于其绑定范围内的准则完全适用于通配符



给定一个这样的类:

  class Foo< T extends Number> {} 

试验编译器接受的内容:




  • A ?使用不相关的接口类型扩展通配符是允许的: Foo <?扩展Runnable> 有效

  • A ?不允许使用不相关的类类型扩展通配符: Foo <? extends Thread> 无效。这很有意义,因为没有类型可以是 Number Thread的子类型

  • 中? super 通配符,通配​​符中的下界必须是类型变量的边界的子类型: Foo <? super Runnable> 是不允许的,因为 Runnable 不是 Number 的子类型。再次,这个限制是非常有意义的。
    但是这些规则在哪里定义?查看 Java语言规范4.5节,我没有看到任何与类有区别的接口;并在应用我对JLS Foo <?的解释时据说超级可运行> 是有效的。所以我可能误解了一些东西。这是我的尝试:



    从JLS的这一部分:


    参数化类型由类或接口名称C和实际类型参数列表组成。如果C不是泛型类或接口的名称,或者实际类型参数列表中的类型参数数量与C的声明类型参数数量不同,那么编译时错误。下面,只要我们说类或接口类型,除非明确排除,否则我们也包含通用版本。在本节中,设A1,...,An为C的形式类型参数,令Bi为Ai的声明范围。符号[Ai:= Ti]表示用类型Ti代替类型变量Ai,对于1 <= i <= n,并且贯穿本说明书使用。

    设P = G 为参数化类型。对于每个实际类型参数Xi,1≤i≤-1,对P进行捕获转换(§5.1.10)后导致类型G< X1,...,Xn> n,Xi <:Bi [A1:= X1,...,An:= Xn](§4.10),或发生编译时错误。

    将其应用于P = Foo <? super runnable> :它给出C = Foo ,n = 1,T1 = ? super runnable 和B1 = Number



    捕捉转换的定义适用: p>


    如果Ti是表单的通配符类型参数? super Bi,那么Si是一个新鲜的类型变量,其上界是Ui [A1:= S1,...,An:= Sn],下界是Bi。 b
    $ b

    这给出了G = Foo 其中 X 是一个新的类型变量,其上限数字和下限 Runnable



    在B1 = Number 中没有类型变量, ,所以Bi [A1:= X1,...,An:= Xn]仍然只是 Number
    X 具有 Number 作为上限(来自捕获转换),并根据子类型规则类型变量的直接超类型是在其绑定中列出的类型中,所以 X <: Number (= Bi [A1:= X1,。 ..,An:= Xn]),所以这个参数在它的范围内。 (但它不是!)



    遵循相同的推理每个通配符都在其范围内,所以这里的某些内容是不正确的。 。但是这个推理究竟在哪里出了问题呢? 另一个洞。对于类型变量的下界几乎没有讨论,我也没有看到任何限制 X 的上限 Number c>和下限 Runnable 。他们可能会将它遗漏出去。



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



    很容易检查上限和下限是否构成一组空类型。所有超类型的下界是已知的;至少它们中的一个应该是上限,否则不存在两个范围内的类型。



    -



    两个 Foo <?在规范中很好地定义了扩展A> 的情况。通过捕获转换,我们获得了新类型变量 X ,其上限 A&数字,规范说明上限 V1& ...& Vm


    如果对于任何两个类(不是接口)Vi和Vj,Vi都不是Vj的子类,那么这是一个编译时错误,反之亦然。


    因此,如果A = Thread,捕捉转换失败。


    With parameterized types in Java, how do the rules that check if a parameter is within its bound work exactly for wildcards?

    Given a class like this:

    class Foo<T extends Number> {}
    

    Experimenting with what the compiler accepts learns that:

    • A ? extends wildcard using an unrelated interface type is allowed: Foo<? extends Runnable> is valid
    • A ? extends wildcard using an unrelated class type is not allowed: Foo<? extends Thread> is invalid. That makes sense because no type can be a subtype of both Number and Thread
    • In a ? super wildcard, the lower bound in the wildcard must be subtype of the bound of the type variable: Foo<? super Runnable> is not allowed because Runnable is not a subtype of Number. Again, this restriction makes perfect sense.

    But where are these rules defined? Looking at the Java Language Specification section 4.5, I don't see anything distinguishing interfaces from classes; and when applying my interpretation of the JLS Foo<? super Runnable> is said to be valid. So I probably misunderstood something. Here's my attempt:

    From that section of the JLS:

    A parameterized type consists of a class or interface name C and an actual type argument list <T1 , ... , Tn>. 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<T1, ..., Tn> 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<X1, ..., Xn>, for each actual type argument Xi, 1 <= i <= n , Xi <: Bi[A1 := X1, ..., An := Xn] (§4.10), or a compile time error occurs.

    Apply that to P = Foo<? super Runnable>: that gives C = Foo, n = 1, T1 = ? super Runnable and B1 = Number.

    For capture conversion this part of the definition of capture conversion applies:

    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.

    That gives G<X1, ..., Xn> = Foo<X> where X is a fresh type variable with upper bound Number and lower bound Runnable. I don't see anything explicitly forbidding such a type variable.

    There are no type variables in B1 = Number, so Bi[A1 := X1, ..., An := Xn] is still simply Number. X has Number as upper bound (coming from the capture conversion), and according to the subtyping rules "The direct supertypes of a type variable are the types listed in its bound", so X <: Number (= Bi[A1 := X1, ..., An := Xn]), so this parameter is within its bounds. (But it isn't!)

    Following the same reasoning every wildcard is within its bounds, so something here isn't right... But where exactly did this reasoning go wrong? How do these rules work when applied correctly?

    解决方案

    JLS on generics is incomplete, and you caught another hole in it. Lower bound on type variables is barely discussed, and I don't see any restriction in spec either on X having upper bound Number and lower bound Runnable. They probably left it out.

    Intuitively, there must be at least one possible type that satisfies both upper bound and lower bound of a type variable, otherwise the variable and all types using the variable would be useless. Since this is almost certainly a programming mistake, compile should fail.

    It's easy to check whether upper bound and lower bound make an empty set of types. All super types of the lower bound are known; at least one of them should be the upper bound, otherwise there is no type that's within both bounds.

    --

    The two Foo<? extends A> cases are well defined in the spec. With capture conversion, we have new type variable X with upper bound A & Number, and the spec says for an upper bound 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.

    Therefore if A=Thread, capture conversion fails.

    这篇关于Java泛型类型中的通配符参数在其范围内的正式条件是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆