使用双括号初始化(匿名内部类)和钻石操作符

12

我想知道为什么第二个使用钻石操作符的 map 声明无法编译,而第一个可以。编译错误:

error: cannot infer type arguments for HashMap; Map map2 = new HashMap<>() { reason: cannot use '<>' with anonymous inner classes where K,V are type-variables: K extends Object declared in class HashMap V extends Object declared in class HashMap

代码:

    Map<String, String> map1 = new HashMap<String, String>() { //compiles fine

        {
            put("abc", "abc");
        }
    };

    Map<String, String> map2 = new HashMap<>() { //does not compile

        {
            put("abc", "abc");
        }
    };

编辑
感谢您的回答-我应该更好地阅读编译错误。 我在JLS中找到了解释。

如果使用“<>”形式为类的类型参数声明匿名类,则这是一个编译时错误。


4
你标题中提到的static初始化程序在哪里? - Jon Skeet
@JonSkeet 你说得对,我记不清“双括号”是怎么称呼的了... - assylias
错误信息非常明显:您已经创建了一个EnumMap的匿名内部类。我猜想这是意外发生的。 - biziclop
@JonSkeet,静态初始化程序就在匿名类中。 - Steve
1
糟糕 - 这是实例初始化程序而不是静态初始化程序。 - Steve
显示剩余2条评论
4个回答

6
你这里没有一个静态初始化器(关键词“static”完全缺失)。
基本上,你创建了一个新的HashMap匿名子类,并在此处定义了实例初始化器块。顺便说一下,这仅在HashMap不是final时才有效。
由于你将获得HashMap的匿名子类,因此钻石操作符在此处不起作用,因为子类将被编译,就好像你写了“... extends HashMap ”,而这显然与“Map ”不兼容。

5
钻石推断无法用于实例化匿名类,而这正是您在此处所做的事情。 尝试这样做:
Map<String, String> map1 = new HashMap<>();

{
    map1.put("abc", "abc");
}

3

这个功能是Project Coin 2的一部分,将在2016年9月22日发布的Java 9中提供。

它被称为允许钻石语法与某些匿名类构造函数

链接。


1
请注意,您也可以完全省略钻石。但是,虽然这样编译,但它仅仅是因为忽略了Java泛型并依赖于Java向后兼容以前的版本。
Map<String, String> map1 = new HashMap() { //compiles fine
    {
        put("abc", "abc");
    }
};

1
正确的...因为它忽略了Java泛型。 - Jeff Fairley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接