在此示例中:
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() 无法编译为:
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()被编译器接受。
compiles()
这个答案说明唯一的区别是,与不同<? ...>,它<T...>允许您稍后引用类型,似乎并非如此。
<? ...>
<T...>
是什么区别<? extends Number>,并<T extends Number>在这种情况下,为什么不第一编译?
<? extends Number>
<T extends Number>
通过使用以下签名定义方法:
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)。
T
Integer
static void compiles(Map<Integer, List<Integer>> map)
关于doesntCompile方法,jls定义了子类型化规则(第4.5.1节,由我加粗):
doesntCompile
如果在以下规则的自反和传递闭包中,证明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
如果在以下规则的自反和传递闭包中,证明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<? extends Number>包含List<Integer>,但Map<Integer, List<? extends Number>>and 并非如此Map<Integer,List<Integer>>。在该SO线程中可以找到有关该主题的更多信息。您仍然可以?通过声明期望使用以下子类型来使带有通配符的版本起作用List<? extends Number>:
? extends Number
List<? extends Number>
List<Integer>
Map<Integer, List<? extends Number>>
Map<Integer,List<Integer>>
?
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>>()); } }