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

时间:2016-02-12 15:41:06

标签: java generics compilation compiler-errors

我们开始在使用泛型的代码上编译错误,并在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
    }
}

产生的错误是:

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

有人有什么想法吗?

1 个答案:

答案 0 :(得分:2)

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

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

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

这意味着您应该如下所示声明Long

foobar

Foobar<...> foobar = new Foobar<...>(); 的类型参数是什么并不重要,只要它存在。它甚至可以是通配符foobar