10

In Java 1.7.0_55, if I write this field declaration, I get a compilation error ("incompatible types"):

   private final Map<String,Object> myMap =
       Collections.synchronizedMap(new HashMap<>());

If I change that to read:

   private final Map<String,Object> myMap =
       Collections.synchronizedMap(new HashMap<String,Object>());

It compiles fine. (I'm using synchronizedMap as an example here, but the same is true for other Collections methods, unmodifiable*, synchronized*, etc)

But why does the diamond operator not work as I would expect here? Since Collections.synchronizedMap() is declared as:

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {

It would seem to me that the type parameters of the constructor invocation must be the same as those of the field declaration, and the compiler should be able to infer the constructed class type parameters based on that.

I tried looking for a clause in the JLS which says this syntax is unacceptable, but I can't find one. Can anyone point me to it?

4

3 回答 3

11

这在 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<>().

于 2014-09-12T23:38:09.433 回答
3

当这样声明一个方法时

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {

类型由参数提供。

假设我这样做:

public <V> V returnV(V v);

然后我称之为:

returnV("myString")

V 由 myString 确定。

当你给

new HashMap<>()

然后没有泛型,所以编译器会猜测你:

new HashMap<Object, Object>()

所以你得到

private final Map<String,Object> myMap =
   Collections.synchronizedMap(new HashMap<Object,Object>());

那就是不兼容的类型错误。

于 2014-09-12T23:30:30.197 回答
0

这是因为您试图传递new HashMap<>()Collections类的方法。这与这样做不同:

Map <String, Integer> map = new HashMap<>();

您使用的方法需要已知类型的 Map。Diamond 语法只是声明和初始化泛型类的标准语法的糖。

于 2014-09-12T23:27:34.650 回答