为什么不能在匿名内部类上使用菱形推断类型?

Mic*_*rry 20 java type-inference java-7

在Java 7及更高版本中,diamond可用于正常推断类型,因此没有问题:

List<String> list = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)

但是,对于像这样的匿名内部类,它不能:

List<String> st = new List<>() { //Doesn't compile

    //Implementation here

}
Run Code Online (Sandbox Code Playgroud)

为什么是这样?从逻辑上讲,在这种情况下,我可以将类型推断为String.这个决定的逻辑原因是,在匿名内部类中实际上不能推断出类型,还是由于其他原因而省略了?

Mik*_*378 12

JSR-334中:

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

我猜想,正如大家都知道的那样,匿名类导致了一代自己的类文件.

我想这些泛型类型不存在于这些文件中,而是由有效(静态)类型替换(因此<String>在声明对象时间由显式类型声明).

实际上,对应于内部类的文件永远不会在它的多个不同实例中共享,那么为什么还要使用泛型呢?:).

编译器强制扩展(通过为泛型添加特殊属性)强制执行这类类文件将更难以实现(并且肯定无用).


irr*_*ble 5

在从stackoverflow跳过帖子后,google产生了http://mail.openjdk.java.net/pipermail/coin-dev/2011-June/003283.html

我猜是这样的,通常匿名类是表观类型的具体子类

    interface Foo<N extends Number>
    {
        void foo(N n);
    }

    Foo<Integer> foo = new Foo<Integer>(){ ... }
Run Code Online (Sandbox Code Playgroud)

    class AnonFoo_1 implements Foo<Integer>{ ... }

    Foo<Integer> foo = new AnonFoo_1();
Run Code Online (Sandbox Code Playgroud)

假设我们允许对匿名类进行菱形推断,那么可能会出现复杂的情况,例如

    Foo<? extends Runnable> foo = new Foo<>(){ ... }
Run Code Online (Sandbox Code Playgroud)

推理规则产生N=Number&Runnable; 遵循上一个实施技巧,我们需要

    class AnonFoo_2 implements Foo<Number&Runnable>{ ... }
Run Code Online (Sandbox Code Playgroud)

目前不允许这样做;从arg到super类型的类型Foo必须是“普通”类型。


但是,理由不是很充分。我们可以发明其他实现技巧来使其工作

    class AnonFoo<N extends Number&Runnable> implements Foo<N>
    {
        @Override public void foo(N n)
        {
            n.intValue();
            n.run();
        }
    }

    Foo<? extends Runnable> foo = new AnonFoo<>();
Run Code Online (Sandbox Code Playgroud)

编译器应该能够做同样的事情。

无论如何,至少编译器应允许大多数不涉及“不可表示类型”的用例,例如Foo<Integer> foo = new Foo<>(){...},很遗憾也禁止了这些常见/简单用例。

  • @Mik378 `new Foo&lt;&gt;()` 和 `new Foo&lt;&gt;() {}` 之间的区别在于,前者是泛型实例化,需要类型擦除,而后者创建扩展参数化类型的非泛型类将以字节代码捕获(您可以在运行时调用 getClass().getGenericSuperclass() 并查看实际的类型参数)。这会产生不可表示类型的问题。事实上,这些问题确实已经存在,例如 `public class Foo&lt;T&gt; { Foo(T t) {} public static void main(String... arg) { new Foo&lt;&gt;((Runnable&amp;CharSequence)null).new Inner () {}; } 类内部 {} }`。 (2认同)