【问题标题】:Why can't Java 7 diamond operator be used with anonymous classes?为什么 Java 7 菱形运算符不能与匿名类一起使用?
【发布时间】:2014-04-07 16:21:48
【问题描述】:

考虑这个试图实例化一些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>() { };

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

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

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

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

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

不支持使用带有匿名内部类的菱形,因为 这样做通常需要对类文件进行扩展 表示不可表示类型的签名属性,事实上的 JVM 改变。

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

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

【问题讨论】:

  • 这不是该特定问题的重复。我引用了一个类似的问题,但需要对答案进行解释(或更好的答案)。
  • 您链接到的答案对您引用的段落的含义给出了“最佳猜测”。你不明白什么?您想要更可靠的答案吗?
  • 感谢@Rafik991,我也阅读了那个答案,但它并没有真正帮助理解任何奇怪的用例。
  • @Radiodef 链接答案中的最佳猜测并没有真正涵盖为什么编译器不能(或选择不)推断正确的类型。一旦知道类型,生成的类应该是相同的。或者也许不是——在这种情况下,任何额外的解释都会有所帮助。

标签: java java-7 diamond-operator


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

       MyHandler<Integer> intHandler = new MyHandler<>(1) {
      
              @Override
              public void handle() {
                  // handling code...
              }
       };
      

      【讨论】:

        【解决方案4】:

        您可以在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...
                }
            };
        }
        

        【讨论】:

          【解决方案5】:

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

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

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

          【讨论】:

          • 非常感谢您的回答。您链接的邮件列表还指向bugs.java.com/bugdatabase/view_bug.do?bug_id=6894753,其中包含更深入的分析以及“困难”类的示例。简而言之,推理不适用于匿名类的原因似乎是支持它的工作不成比例。
          • JDK 9 的解决方案非常简单:只允许可表示类型。具有讽刺意味的是,他们想要避免的问题已经存在。考虑public class Foo&lt;T&gt; { Foo(T t) {} public static void main(String... arg) { System.out.println( new Foo&lt;&gt;("".getClass()).new Inner() {} .getClass().getGenericSuperclass()); } class Inner {} }。这捕获了无法用字节码表示的不可表示类型。在JDK 11之前,会产生无效的字节码,从JDK 11开始,会产生编译错误“illegal signature attribute”,没有解释。
          猜你喜欢
          • 2016-03-15
          • 2011-05-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-01-24
          • 2022-12-03
          • 1970-01-01
          • 2013-04-27
          相关资源
          最近更新 更多