22

在 Java 7 及更高版本中,菱形可用于正常推断类型,如下所示:

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

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

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

    //Implementation here

}

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

4

3 回答 3

14

JSR-334中:

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

我的猜测是,众所周知,匿名类会导致生成自己的类文件。

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

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

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

于 2012-12-11T14:30:45.750 回答
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>{ ... }

目前不允许这样做;类型 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<>(){...}遗憾的是,这些常见/简单的情况也被不必要地禁止了。

于 2012-12-11T15:24:06.827 回答
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

于 2012-12-11T13:47:59.543 回答