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

时间:2012-12-11 13:35:08

标签: java java-7 type-inference

在Java 7及更高版本中,可以使用菱形来正常推断类型,而不会出现问题:

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

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

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

    //Implementation here

}

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

3 个答案:

答案 0 :(得分:12)

JSR-334

  

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

我猜想,每个人都知道,匿名类导致了一代自己的类文件。

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

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

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

答案 1 :(得分:5)

从stackoverflow中跳过帖子后,谷歌收益率为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>{ ... }

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


然而,理由并不是很强烈。我们可以发明其他实现技巧来使其工作

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

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

在任何情况下,至少编译器应该允许大多数不涉及“undenotable类型”的用例,例如Foo<Integer> foo = new Foo<>(){...}遗憾的是,这些常见/简单的情况也是不必要的。

答案 2 :(得分:1)

简而言之,<>几乎无法推断类型,它会关闭没有它的警告。

编辑:正如@Natix所指出的,它会进行一些检查。

List<Integer> ints = new ArrayList<>();
List<String> copy = new ArrayList<>(ints);

产生编译错误

Error:Error:line (42)error: incompatible types
required: List<String>
found:    ArrayList<Integer>

正如您所看到的,<>采用了参数的类型,而不是根据copy

的类型推断类型
相关问题