为什么 Java 7 钻石运算符不能与匿名类一起使用?

2022-09-01 04:00:11

考虑以下 Java 代码,它尝试实例化一些 s:List

List<String> list1 = new ArrayList<String>();
List<String> list2 = new ArrayList<>();
List<String> list3 = new ArrayList<String>() { };
List<String> list4 = new ArrayList<>() { };
List<String> list5 = new ArrayList<Integer>() { };

list1并且直截了当; 在 Java 7 中使用新的菱形运算符来减少类型参数的不必要重复。list2list2

list3是使用匿名类的变体,可能会覆盖 的某些方法。list1ArrayList

list4尝试使用菱形运算符,类似于 ,但这是一个编译错误,消息“<>”不能与匿名类一起使用list2

list5产生一个错误,证明编译器知道实际需要哪种类型。错误消息是类型不匹配: 无法从新的 ArrayList<Integer>(){} 转换为 List<String>

那么,有了 的声明,为什么钻石运算符不能与匿名类一起使用呢?这里有一个类似的问题,其中包含一个被接受的答案,其中包含JSR-334的以下解释:list4

不支持将菱形与匿名内部类一起使用,因为这样做通常需要扩展类文件签名属性以表示不可识别的类型,这是事实上的 JVM 更改。

我需要一些帮助来理解这种推理。为什么显式类型与相同且显然容易推断的类型需要在生成的类文件中有任何差异?“一般情况下这样做”将涵盖哪些困难的用例?

这背后的原因是什么?


答案 1

这在“Project Coin”邮件列表中进行了讨论。实质上(强调我的):

在内部,Java编译器在一组比可以在Java程序中显式写下的类型更丰富的类型上运行。无法在 Java 程序中编写的编译器内部类型称为不可通知类型。不可识别的类型可能是由于菱形使用的推论而发生的。因此,不支持将菱形与匿名内部类一起使用,因为这样做通常需要扩展类文件签名属性以表示不可识别的类型,这是事实上的 JVM 更改。未来的平台版本可以在创建匿名内部类时使用菱形,只要推断的类型是可注意的。

请注意,Java 8 也不支持它,但将作为 Java 9 中的新功能包含在其中(“Milling Project Coin”的第 3 项)。


答案 2

您可以在Java9中使用钻石操作器

MyHandler<Integer> intHandler = new MyHandler<>(1) {

        @Override
        public void handle() {
            // handling code...
        }
    };

    MyHandler<? extends Integer> intHandler1 = new MyHandler<>(10) {

        @Override
        void handle() {
            // handling code...
        }
    };

    MyHandler<?> handler = new MyHandler<>("One hundred") {

        @Override
        void handle() {
            // handling code...
        }
    };
}

推荐