Javac之glb与lub

本文深入探讨Java泛型中的捕获转换机制,解析从参数化类型G<T1>到G<S1>的转换过程,包括类型变量、上界和下界的处理。同时,详细解释最小上界(lub)的概念及其计算方法,帮助读者理解如何在不同类型的泛型参数间找到最具体的共享超类型。

 

 

5.1.10. Capture Conversion

Let G name a generic type declaration (§8.1.2, §9.1.2) with n type parameters A1,...,An with corresponding bounds U1,...,Un.

There exists a capture conversion from a parameterized type G<T1,...,Tn> (§4.5) to a parameterized type G<S1,...,Sn>, where, for 1 i n :

  • If Ti is a wildcard type argument (§4.5.1) of the form ?, then Si is a fresh type variable whose upper bound is Ui[A1:=S1,...,An:=Sn] and whose lower bound is the null type (§4.1).

  • If Ti is a wildcard type argument of the form ? extends Bi, then Si is a fresh type variable whose upper bound is glb(Bi, Ui[A1:=S1,...,An:=Sn]) and whose lower bound is the null type.

    glb(V1,...,Vm) is defined as 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.

  • 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.

  • Otherwise, Si = Ti.

Capture conversion on any type other than a parameterized type (§4.5) acts as an identity conversion (§5.1.1).

Capture conversion is not applied recursively.

就是说在G<T1>到G<S1>的过程中可能T1类型也是T1<X>这样的类型。

Capture conversion never requires a special action at run time and therefore never throws an exception at run time.

 

 

4.10.4. Least Upper Bound

 

 

List<String>

List<Object>

ST(Ui)

the set of supertypes of Ui.

ST(List<String>)=

List<String>

Collection<String>

Object 

ST(List<Object>)=

List<Object>

Collection<Object>

Object 

EST(Ui)

the set of erased supertypes of U

EST(List<String>)=

List

Collection

Object 

EST(List<Object>)=

List

Collection

Object

}

EC

the intersection of all the sets EST(Ui

EC =

List

Collection

Object 

}

MEC

the minimal erased candidate set

for U1 ... Uk

MEC =

List 

}

Relevant(G)

Relevant(G) =

V | 1≤ik:

V in ST(Ui) and V=G<...> 

}

Relevant(List) =

List<String>

List<Object>

}

 

The least upper bound, or "lub", of a set of reference types is a shared supertype that is more specific than any other shared supertype (that is, no other shared supertype is a subtype of the least upper bound). This type, lub(U1, ..., Uk), is determined as follows.

 If k = 1, then the lub is the type itself: lub(U) = U.

 Otherwise:

  •  For each Ui (1 i k):

     Let ST(Ui) be the set of supertypes of Ui.

     Let EST(Ui), the set of erased supertypes of Ui, be:

     EST(Ui) = { |W| | W in ST(Ui) } where |W| is the erasure of W.

    The reason for computing the set of erased supertypes is to deal with situations where the set of types includes several distinct parameterizations of a generic type.

    For example, given List<String> and List<Object>, simply intersecting the sets ST(List<String>) = { List<String>, Collection<String>, Object } and ST(List<Object>) = { List<Object>, Collection<Object>, Object } would yield a set { Object }, and we would have lost track of the fact that the upper bound can safely be assumed to be a List.

    In contrast, intersecting EST(List<String>) = { List, Collection, Object } and EST(List<Object>) = { List, Collection, Object } yields { List, Collection, Object }, which will eventually enable us to produce List<?>.

  • Let EC, the erased candidate set for U1 ... Uk, be the intersection of all the sets EST(Ui) (1 i k).

  •  Let MEC, the minimal erased candidate set for U1 ... Uk, be:

     MEC = { V | V in EC, and for all W V in EC, it is not the case that W <: V }

    Because we are seeking to infer more precise types, we wish to filter out any candidates that are supertypes of other candidates. This is what computing MEC accomplishes. In our running example, we had EC = { List, Collection, Object }, so MEC = { List }. The next step is to recover type arguments for the erased types in MEC.

  •  For any element G of MEC that is a generic type:

     Let the "relevant" parameterizations of G, Relevant(G), be:

     Relevant(G) = { V | 1 i k: V in ST(Ui) and V = G<...> }

    In our running example, the only generic element of MEC is List, and Relevant(List) = { List<String>, List<Object> }. We will now seek to find a type argument for List that contains (§4.5.1) both String and Object.

    This is done by means of the least containing parameterization (lcp) operation defined below. The first line defines lcp() on a set, such as Relevant(List), as an operation on a list of the elements of the set. The next line defines the operation on such lists, as a pairwise reduction on the elements of the list. The third line is the definition of lcp() on pairs of parameterized types, which in turn relies on the notion of least containing type argument (lcta). lcta() is defined for all possible cases.

    Let the "candidate" parameterization of G, Candidate(G), be the most specific parameterization of the generic type G that contains all the relevant parameterizations of G:

     Candidate(G) = lcp(Relevant(G))  // Relevant(G)经过lcp运算后就会得到the most specific parameterization of the generic type G

     where lcp(), the least containing invocation, is:

    •  lcp(S) = lcp(e1, ..., en) where ei (1 i n) in S  // 第一行定义了lcp()

    •  lcp(e1, ..., en) = lcp(lcp(e1, e2), e3, ..., en) // 第二行两两来减少列表中的元素

    •  lcp(G<X1, ..., Xn>, G<Y1, ..., Yn>) = G<lcta(X1, Y1), ..., lcta(Xn, Yn)> // 依赖lcta进行操作,lcta列举出了两个元素的所有情况

    •  lcp(G<X1, ..., Xn>) = G<lcta(X1), ..., lcta(Xn)>

     and where lcta(), the least containing type argument, is: (assuming U and V are types)

    •  lcta(U, V) = U if U = V, otherwise ? extends lub(U, V)

    •  lcta(U, ? extends V) = ? extends lub(U, V)

    •  lcta(U, ? super V) = ? super glb(U, V)

    •  lcta(? extends U, ? extends V) = ? extends lub(U, V)

    •  lcta(? extends U, ? super V) = U if U = V, otherwise ?

    •  lcta(? super U, ? super V) = ? super glb(U, V)

    •  lcta(U) = ? if U's upper bound is Object, otherwise ? extends lub(U,Object)

     and where glb() is as defined in §5.1.10.

  •  Let lub(U1 ... Uk) be:

     Best(W1) & ... & Best(Wr)

     where Wi (1 i r) are the elements of MEC, the minimal erased candidate set of U1 ... Uk;

     and where, if any of these elements are generic, we use the candidate parameterization (so as to recover type arguments):

     Best(X) = Candidate(X) if X is generic; X otherwise.

Strictly speaking, this lub() function only approximates a least upper bound. Formally, there may exist some other type T such that all of U1 ... Uk are subtypes of T and T is a subtype of lub(U1, ..., Uk). However, a compiler for the Java programming language must implement lub() as specified above.

It is possible that the lub() function yields an infinite type. This is permissible, and a compiler for the Java programming language must recognize such situations and represent them appropriately using cyclic data structures.

The possibility of an infinite type stems from the recursive calls to lub(). Readers familiar with recursive types should note that an infinite type is not the same as a recursive type.

 

 

The declared type of an exception parameter that denotes its type as a union with alternatives D1 | D2 | ... | Dn is lub(D1D2, ..., Dn) (§15.12.2.7). 

参考:https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.20

 

参考:

(1)https://docs.oracle.com/javase/specs/jls/se8/html/jls-4.html

(2)https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.10

转载于:https://www.cnblogs.com/extjs4/p/7518770.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值