<有什么区别?扩展Base> < T扩展Base&gt ;? [英] What is the difference between <? extends Base> and <T extends Base>?

查看:74
本文介绍了<有什么区别?扩展Base> < T扩展Base&gt ;?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在此示例中:

import java.util.*;

public class Example {
    static void doesntCompile(Map<Integer, List<? extends Number>> map) {}
    static <T extends Number> void compiles(Map<Integer, List<T>> map) {}

    static void function(List<? extends Number> outer)
    {
        doesntCompile(new HashMap<Integer, List<Integer>>());
        compiles(new HashMap<Integer, List<Integer>>());
    }
}

doesntCompile()无法编译为:

Example.java:9: error: incompatible types: HashMap<Integer,List<Integer>> cannot be converted to Map<Integer,List<? extends Number>>
        doesntCompile(new HashMap<Integer, List<Integer>>());
                      ^

compiles()被编译器接受.

此答案解释说,唯一的区别是与<? ...>不同,<T ...>允许您稍后引用类型,似乎并非如此.

This answer explains that the only difference is that unlike <? ...>, <T ...> lets you reference the type later, which doesn't seem to be the case.

在这种情况下,<? extends Number><T extends Number>有什么区别?为什么不首先编译?

What is the difference between <? extends Number> and <T extends Number> in this case and why doesn't the first compile?

推荐答案

通过定义具有以下签名的方法:

By defining the method with the following signature:

static <T extends Number> void compiles(Map<Integer, List<T>> map) {}

并像这样调用它:

compiles(new HashMap<Integer, List<Integer>>());

在jls中§ 8.1.2 我们发现,(有趣的部分被我加粗了):

In the jls §8.1.2 we find, that (interesting part bolded by me):

通用类声明定义了一组参数化类型(第4.5节),对于类型实参的每种可能的调用,每个类型实参一个.所有这些参数化类型在运行时都共享同一类.

A generic class declaration defines a set of parameterized types (§4.5), one for each possible invocation of the type parameter section by type arguments. All of these parameterized types share the same class at run time.

换句话说,类型T与输入类型匹配,并分配了Integer.签名将有效地变为static void compiles(Map<Integer, List<Integer>> map).

In other words, the type T is matched against the input type and assigned Integer. The signature will effectively become static void compiles(Map<Integer, List<Integer>> map).

对于doesntCompile方法,jls定义了子类型化规则(

When it comes to doesntCompile method, jls defines rules of subtyping (§4.5.1, bolded by me):

如果类型T2表示的类型集可证明是T1的自反和传递闭包下的T1表示的类型集的子集,则说类型自变量T1包含另一个类型的自变量T2,写为T2< = T1.下列规则(其中< ;:表示子类型(§4.10)):

A type argument T1 is said to contain another type argument T2, written T2 <= T1, if the set of types denoted by T2 is provably a subset of the set of types denoted by T1 under the reflexive and transitive closure of the following rules (where <: denotes subtyping (§4.10)):

  • ?扩展T< =?如果T< ;: S

  • ? extends T <= ? extends S if T <: S

?扩展T< =?

? extends T <= ?

?超级T< =?如果S< ;: T

? super T <= ? super S if S <: T

?超级T< =?

? super T <= ?

?超级T< =?扩展对象

? super T <= ? extends Object

T< = T

T <= T

T< =吗?扩展T

T< =?超级T

T <= ? super T

这意味着? extends Number确实包含Integer甚至List<? extends Number>包含List<Integer>,但Map<Integer, List<? extends Number>>Map<Integer, List<Integer>>并非如此.有关该主题的更多信息,可以在此SO线程中中找到.您仍然可以通过声明您期望List<? extends Number>的子类型来使带有?通配符的版本起作用:

This means, that ? extends Number indeed contains Integer or even List<? extends Number> contains List<Integer>, but it's not the case for Map<Integer, List<? extends Number>> and Map<Integer, List<Integer>>. More on that topic can be found in this SO thread. You can still make the version with ? wildcard work by declaring, that you expect a subtype of List<? extends Number>:

public class Example {
    // now it compiles
    static void doesntCompile(Map<Integer, ? extends List<? extends Number>> map) {}
    static <T extends Number> void compiles(Map<Integer, List<T>> map) {}

    public static void main(String[] args) {
        doesntCompile(new HashMap<Integer, List<Integer>>());
        compiles(new HashMap<Integer, List<Integer>>());
    }
}

这篇关于&lt;有什么区别?扩展Base&gt; &lt; T扩展Base&gt ;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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