本文主要介绍Java中,使用泛型时<? extends Base> 和 <T extends Base>的区别,以及异常和正常使用和<? extends Number>和<T extends Number>的示例代码。

使用出现异常代码:

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

通过使用以下签名定义方法:

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

如下代码调用:

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

 §8.1.2 中介绍内容泛型类声明定义了一组参数化类型(§4.5),每个类型参数都可以调用类型参数部分。所有这些参数化类型在运行时共享同一个类。

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

关于doesntCompile方法,jls定义了子类型化规则(第4.5.1节,):

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

如此说明,? extends Number确实包含Integer甚至List<? extends Number>包含List<Integer>,但Map<Integer, List<? extends Number>> 并非如此Map<Integer, List<Integer>>。您仍然可以?通过声明期望使用以下子类型来使带有通配符的版本起作用List<? extends Number>

public class Example {
    // 可以正常编译
    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>>());
    }
}

推荐文档