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

时间:2014-03-05 14:30:57

标签: java java-7 diamond-operator

考虑这个尝试实例化某些List的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>() { };

list1list2很简单; list2使用Java 7中的新菱形运算符来减少不必要的类型参数重复。

list3list1使用匿名类的变体,可能会覆盖ArrayList的某些方法。

list4尝试使用菱形运算符,类似于list2,但这是编译错误,消息'&lt;&gt;'不能与匿名类一起使用

list5产生错误,证明编译器知道实际需要什么类型。错误消息是类型不匹配:无法从新的ArrayList&lt; Integer&gt;(){}转换为List&lt; String&gt;

那么,在list4的声明中,为什么钻石运算符不能与匿名类一起使用? similar question here有一个已接受的答案,其中包含JSR-334中的以下说明:

  

从那时起,不支持将菱形与匿名内部类一起使用   这样做通常需要扩展类文件   signature属性表示不可表示的类型,事实上的JVM   变化

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

这是什么原因?

4 个答案:

答案 0 :(得分:21)

这在the "Project Coin" mailing list上进行了讨论。实质上(强调我的):

  

在内部,Java编译器在比一组更丰富的类型上运行   那些可以在Java程序中明确写下来的。该   无法在Java程序中编写的编译器内部类型   称为不可表示的类型。结果可能出现不可表示的类型   钻石使用的推论。 因此,使用钻石   不支持匿名内部类,因为通常会这样做   要求扩展类文件签名属性来表示   不可表示的类型,事实上的JVM更改 。未来是可行的   平台版本可以允许在创建匿名时使用菱形   内部类,只要推断类型是可表示的。

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

答案 1 :(得分: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...
        }
    };
}

答案 2 :(得分:1)

您可以在java 9中使用它 Example Diamond operator

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

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

答案 3 :(得分:0)

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>() { };