We've started getting compile errors on code that used generics and that compiled successfully under Java 6. Here's a simple class to reproduce:
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
}
}
The resulting error is:
Test.java:26: error: incompatible types: Object cannot be converted to Long
Long fb = foobar.get(); // This generates a compile time error
Does anybody have any ideas?
This is because Foobar
without any type parameters is a raw type. Raw types have no generic abilities, so in this case the raw type Foobar
extends Bar
which extends the raw type Foo
. Raw types use the upper bound of their parameters, as they are compiled that way after erasure and the compiler has no type parameters to safely insert casts.
In the case of Foo
, this upper bound is Object
. This causes Foo.get()
to return Object
, so Bar.get()
returns Object
, and so Foobar.get()
returns Object
as well. Obviously, the compiler won't cast Object
to Long
without an explicit cast.
In contrast, the parameterized type Foobar<N>
extends Bar
which extends the parameterized type Foo<Long>
. The compiler can now use generics, so it sees that Foo<T>.get()
has type T
, that Foo<Long>.get()
has type Long
, that Bar.get()
has type Long
, and finally that Foobar<N>.get()
has type Long
as well.
This means that you should declare foobar
as shown:
Foobar<...> foobar = new Foobar<...>();
It doesn't matter what the type parameter of foobar
is, just as long as it is present. It can even be the wildcard ?
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With