Java通用编译时错误从Java 6迁移到7或8

Mic*_*yen 7 java generics compiler-errors compilation

我们已经开始在使用泛型的代码上编译错误,并且在Java 6下成功编译.这是一个简单的类来重现:

class Test {
    static class Foo<T> {
            T t;
            Foo(T t) { this.t = t; }
            T get() { return t; }
    }

    static class Bar extends Foo<Long> {
            Bar(Long t) { super(t); }
    }

    static class Foobar<N extends Number> extends Bar {
            Foobar() { super(5L); }
    }

    public static void main(String[] args) {
            Bar bar = new Bar(0L);
            Long b = bar.get();             // This works
            Foobar foobar = new Foobar();
            Long fb = foobar.get(); // This generates a compile time error
    }
}
Run Code Online (Sandbox Code Playgroud)

产生的错误是:

Test.java:26: error: incompatible types: Object cannot be converted to Long
            Long fb = foobar.get(); // This generates a compile time error
Run Code Online (Sandbox Code Playgroud)

有人有什么想法吗?

HTN*_*TNW 2

这是因为Foobar没有任何类型参数是原始类型。原始类型没有通用能力,因此在这种情况下,原始类型Foobar扩展Bar原始类型Foo。原始类型使用其参数的上限,因为它们是在擦除后以这种方式编译的,并且编译器没有类型参数来安全地插入强制转换。

在 的情况下Foo,该上限为Object。这会导致Foo.get()return Object,因此Bar.get()返回Object,因此也Foobar.get()返回。显然,如果没有显式强制转换Object,编译器不会强制转换。ObjectLong

相反,参数化类型Foobar<N>extendsBar扩展了参数化类型Foo<Long>。编译器现在可以使用泛型,因此它会看到Foo<T>.get()具有 type TFoo<Long>.get()具有 type LongBar.get()具有 type Long、最后Foobar<N>.get()具有 type Long

这意味着您应该foobar如下声明:

Foobar<...> foobar = new Foobar<...>();
Run Code Online (Sandbox Code Playgroud)

参数的类型是什么并不重要foobar,只要它存在即可。它甚至可以是通配符?

  • 但是,为什么 raw 类型可以在 1.6 中使用呢?我不知道 1.7 中对泛型有任何更改(除了类型推断) (2认同)