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

2022-09-01 23:39:56

在 Java 7 及更高版本中,菱形可用于推断正常情况下的类型,而不会出现问题:

List<String> list = new ArrayList<>();

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

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

    //Implementation here

}

这是为什么呢?从逻辑上讲,在这种情况下,我绝对可以将类型推断为.对于这个决定,是否有合乎逻辑的原因,其中类型实际上不能在匿名内部类上推断出来,或者由于其他原因而被省略?String


答案 1

JSR-334 中

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

我猜想的是,众所周知,匿名类会导致一代自己的类文件。

我想象泛型类型不存在于这些文件中,而是被有效(静态)类型所取代(因此由显式类型声明,如在声明对象时)。<String>

事实上,对应于内部类的文件永远不会在它的多个不同实例之间共享,那么为什么要在泛型中打扰它?!:).

对于编译器来说,强制扩展(通过为泛型添加特殊属性)到这些类文件中是更难实现的(当然也是无用的)。


答案 2

谷歌收益率,在跳过堆栈溢出的帖子后,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>(){ ... }

由实现

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

    Foo<Integer> foo = new AnonFoo_1();

假设我们允许在匿名类上进行钻石推断,可能会有复杂的情况,例如

    Foo<? extends Runnable> foo = new Foo<>(){ ... }

推理规则产生 ;按照上一个实现技巧,我们需要N=Number&Runnable

    class AnonFoo_2 implements Foo<Number&Runnable>{ ... }

这是目前不允许的。类型 arg 到超类型必须是“普通”类型。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<>();

编译器应该能够做同样的技巧。

无论如何,至少编译器应该允许大多数不涉及“不值得注意的类型”的用例,就像很遗憾,这些常见/简单的情况也被不必要地禁止了。Foo<Integer> foo = new Foo<>(){...}


推荐