我们开始在使用泛型的代码上编译错误,并在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
有人有什么想法吗?
答案 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
。