Dev*_*ull 29 java generics dictionary jvm arraylist
在这个例子中:
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>>());
}
}
Run Code Online (Sandbox Code Playgroud)
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>>());
^
Run Code Online (Sandbox Code Playgroud)
whilecompiles()被编译器接受。
这个答案解释了唯一的区别是不同<? ...>,<T ...>让您稍后引用类型,这似乎并非如此。
是什么区别<? extends Number>,并<T extends Number>在这种情况下,为什么不第一编译?
And*_*cus 15
通过使用以下签名定义方法:
static <T extends Number> void compiles(Map<Integer, List<T>> map) {}
Run Code Online (Sandbox Code Playgroud)
并像这样调用它:
compiles(new HashMap<Integer, List<Integer>>());
Run Code Online (Sandbox Code Playgroud)
您正在匹配T您提供的类型。
在 jls §8.1.2 中,我们发现(有趣的部分由我加粗):
泛型类声明定义了一组参数化类型(第 4.5 节),一个用于通过类型参数对类型参数部分的每次可能调用。所有这些参数化类型在运行时共享同一个类。
换句话说,类型T与输入类型相匹配并被赋值Integer。签名将有效地变为static void compiles(Map<Integer, List<Integer>> map).
说到doesntCompile方法,jls 定义了子类型的规则(第4.5.1 节,我加粗):
一个类型参数 T1 被称为包含另一个类型参数 T2,写作 T2 <= T1,如果 T2 表示的类型集在以下规则的自反和传递闭包下可证明是 T1 表示的类型集的子集(其中 <: 表示子类型(第 4.10 节)):
? 扩展 T <= ? 扩展 S 如果 T <: S
? 扩展 T <= ?
? 超级 T <= ? 超级 S 如果 S <: T
? 超级 T <= ?
? 超级 T <= ? 扩展对象
T <= T
T <= ? 扩展 T
T <= ? 超级T
这意味着,? extends Number确实包含Integer甚至List<? extends Number>包含List<Integer>,但情况并非如此Map<Integer, List<? extends Number>>和Map<Integer, List<Integer>>。可以在此 SO 线程中找到有关该主题的更多信息。您仍然可以?通过声明您期望的子类型来使带有通配符的版本工作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>>());
}
}
Run Code Online (Sandbox Code Playgroud)
在通话中:
compiles(new HashMap<Integer, List<Integer>>());
Run Code Online (Sandbox Code Playgroud)
T 与 Integer 匹配,因此参数的类型是 a Map<Integer,List<Integer>>。方法不是这种情况doesntCompile:Map<Integer, List<? extends Number>>无论调用中的实际参数是什么,参数的类型都保持不变;这不能从HashMap<Integer, List<Integer>>.
更新
在该doesntCompile方法中,没有什么可以阻止您执行以下操作:
static void doesntCompile(Map<Integer, List<? extends Number>> map) {
map.put(1, new ArrayList<Double>());
}
Run Code Online (Sandbox Code Playgroud)
很明显,它不能接受 aHashMap<Integer, List<Integer>>作为参数。
| 归档时间: |
|
| 查看次数: |
1426 次 |
| 最近记录: |