This is because Foobar without any type parameters, is a raw type. Raw types do not have common capabilities, so in this case, the raw Foobar type extends Bar , which extends the original Foo type. Raw types use the upper bound of their parameters because they are compiled this way after being deleted, and the compiler does not have type parameters for safely inserting labels.
In the case of Foo this upper bound is Object . This results in the return of Foo.get() Object , so Bar.get() returns Object , and therefore Foobar.get() returns Object . Obviously, the compiler will not distinguish 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() is of type T , that Foo<Long>.get() is of type Long , that Bar.get() is of type Long , and finally Foobar<N>.get() is of type Long >.
This means that you must declare Foobar as shown:
Foobar<...> foobar = new Foobar<...>();
It does not matter what a parameter of type Foobar , as long as it is present. Could it even be a template ? .
HTNW
source share