在Java 1.7.0_55中,如果我写这个字段声明,我会收到编译错误(“不兼容的类型”):
private final Map<String,Object> myMap =
Collections.synchronizedMap(new HashMap<>());
如果我将其改为:
private final Map<String,Object> myMap =
Collections.synchronizedMap(new HashMap<String,Object>());
编译好。 (我在这里使用synchronizedMap作为示例,但其他集合方法也是如此,不可修改*,同步*等)
但是为什么钻石操作员不像我期望的那样工作?由于Collections.synchronizedMap()声明为:
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
在我看来,构造函数调用的类型参数必须与字段声明的类型参数相同,编译器应该能够根据它推断构造的类类型参数。
我试图在JLS中寻找一个条款,说这种语法是不可接受的,但我找不到。有人能指出我吗?
答案 0 :(得分:10)
这在Java 7中因编译错误而失败,但它在Java 8中成功编译。简而言之,编译器的类型推断没有捕获Java 7中正确的推断类型,但更好的类型推断推断出Java 8中适当的类型。
此更改为JEP (JDK Enhancement Proposal) 101 for Java 8。
<强>摘要强>
平滑地扩展方法类型推断的范围,以支持(i)方法上下文中的推理和(ii)链式调用中的推理。
Java 8能够通过多个方法调用使用参数和方法调用链来推断类型。现在,它可以从作业<String, Object>
的左侧通过调用Collections.synchronizedMap
到该调用的参数new HashMap<>()
中的菱形运算符来确定。
答案 1 :(得分:3)
当声明方法时
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
genrecis由参数提供。
让我这样说:
public <V> V returnV(V v);
然后我称之为:
returnV("myString")
V是myString的detrmind。
当你提供
new HashMap<>()
然后没有泛型,所以编译器猜测你:
new HashMap<Object, Object>()
所以你得到了
private final Map<String,Object> myMap =
Collections.synchronizedMap(new HashMap<Object,Object>());
那就是和不兼容的类型错误。
答案 2 :(得分:0)
这是因为您试图将new HashMap<>()
传递给Collections
类的方法。这不同于:
Map <String, Integer> map = new HashMap<>();
您正在使用的方法需要已知类型的Map。 Diamond语法只是声明和初始化泛型类的标准语法的糖。