通过使用以下签名定义方法:
static <T extends Number> void compiles(Map<Integer, List<T>> map) {}并像这样调用它:
compiles(new HashMap<Integer, List<Integer>>());
在jls§8.1.2中,我们发现(有趣的部分被我加粗了):
通用类声明定义了一组参数化类型(第4.5节), 每种可能通过类型arguments调用类型参数节的类型 。所有这些参数化类型在运行时共享同一类。
换句话说,将类型
T与输入类型进行匹配并进行分配
Integer。签名将有效地变为
static void compiles(Map<Integer,List<Integer>> map)。
关于
doesntCompile方法,jls定义了子类型化规则(第4.5.1节,由我加粗):
如果在以下规则的自反和传递闭包中,证明T2表示的类型集是T1表示的类型集的子集,则类型自变量T1包含另一个类型自变量T2,写为T2 <=
T1。其中<:表示子类型(§4.10)):
?扩展T <=?如果T <:S则扩展S
?扩展T <=?
?超级T <=?如果S <:T则为超级S
?超级T <=?
?超级T <=?扩展对象
T <= T
T <=?延伸T
T <=?超级T
这意味着,
? extends Number确实包含
Integer,甚至
List<? extendsNumber>包含
List<Integer>,但
Map<Integer, List<? extends Number>>and
并非如此
Map<Integer,List<Integer>>。在该SO线程中可以找到有关该主题的更多信息。您仍然可以
?通过声明期望使用以下子类型来使带有通配符的版本起作用
List<? extendsNumber>:
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>>()); }}


