< 和有什么不一样?扩展基础>和<T扩展基数>? [英] What is the difference between <? extends Base> and <T extends Base>?

查看:20
本文介绍了< 和有什么不一样?扩展基础>和<T扩展基数>?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这个例子中:

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> 在这种情况下,为什么第一个不编译?

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>>());

您正在将 T 与您提供的类型进行匹配.

you're matching T against the type you're providing.

在 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> 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 定义了子类型化规则(§4.5.1,由我加粗):

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

一个类型参数 T1 被称为包含另一个类型参数 T2,写作 T2 <= T1,如果 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 <= ?

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

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

?超级 T <= ?

?超级 T <= ?扩展对象

? super T <= ? extends Object

T <= T

T <= ?扩展 T

T <= ?超级T

这意味着,那个?extends Number 确实包含 Integer 甚至 List 包含 List,但是 Map>Map>.可以在在此 SO 线程中找到有关该主题的更多信息.您仍然可以通过声明您期望 List<?扩展数>:

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; 和有什么不一样?扩展基础>和&lt;T扩展基数&gt;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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