38

考虑这个试图实例化一些Lists 的 Java 代码:

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并且list2直截了当;list2使用 Java 7 中的新菱形运算符来减少类型参数的不必要重复。

list3list1使用匿名类的一种变体,可能会覆盖ArrayList.

list4尝试使用菱形运算符,类似于list2,但这是一个编译错误,消息'<>' cannot be used with anonymous classes

list5产生一个错误,证明编译器知道实际需要什么类型。错误消息是Type mismatch: cannot convert from new ArrayList<Integer>(){} to List<String>

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

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

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

造成这种情况的根本原因是什么?

4

5 回答 5

23

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

在内部,Java 编译器操作的类型集比可以在 Java 程序中显式编写的类型集更丰富。不能在 Java 程序中编写的编译器内部类型称为不可表示类型。由于 diamond 使用的推理结果,可能会出现不可表示的类型。因此,不支持将 diamond 与匿名内部类一起使用,因为这样做通常需要对类文件签名属性进行扩展以表示不可表示的类型,这是事实上的 JVM 更改。只要推断的类型是可表示的,未来的平台版本可以在创建匿名内部类时允许使用 diamond 是可行的。

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

于 2014-03-05T14:51:53.700 回答
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...
        }
    };
}
于 2017-10-28T09:30:56.253 回答
2

您可以在 java 9 Example Diamond 运算符中使用它

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

        @Override
        public void handle() {
            // handling code...
        }
 };
于 2017-10-28T09:33:22.790 回答
1

Java 10开始,您可以轻松地使用var,编译器将负责类型推断。

var list1 = new ArrayList();
var list2 = new ArrayList<String>();
var list3 = new ArrayList<String>() { };
var list4 = new ArrayList<>() { };
var list5 = new ArrayList<Integer>() { };
于 2018-03-31T04:36:57.200 回答
0

从 Java 9 开始,菱形运算符 <> 可以与匿名类一起使用。见这里

于 2021-09-27T10:51:53.017 回答