Reputation: 109
I have the following code:
public class Foo {
interface Coo<T> {
public T cool();
}
abstract class Bar<T extends Bar<T>> implements Coo<T> {
@SuppressWarnings("unchecked")
T doSomething() {
return (T) this;
}
@SuppressWarnings("unchecked")
@Override
public T cool() {
return (T) this;
}
}
class FooBar extends Bar<FooBar> {
@Override
public FooBar cool() {
return super.cool();
}
}
}
Why is the cast to (this) object type unsafe? When Bar implements Coo, isn't the generic saying that returned cool must be of type T, which extends Bar or its subclasses?
Upvotes: 1
Views: 313
Reputation: 122449
T
extends Bar<T>
, but Bar<T>
(the type of this
) does not extend T
.
Imagine
class A extends Bar<A> { ... }
class B extends Bar<A> { ... }
Then the method becomes inherited as:
class B {
A doSomething() {
return (A) this;
}
}
which is obviously not right.
It is not possible to do what you want with generics. It is a big misconception among people. They think that recursive bounds will allow you to do self-types. But recursive bounds are ALMOST NEVER useful in Java. 99% of the places where you see people write interface Bar<T extends Bar<T>>
, it would be just as good to write it as interface Bar<T>
.
Upvotes: 1
Reputation: 14718
Because this
in Bar
has type Bar<T extends Bar<T>>
but not T
, the compiler generates warnings for Bar#doSomething
. The following won't generate any warnings:
abstract class Bar<T extends Bar<T>> {
Bar<T> doSomething() {
return this;
}
}
The body of Bar#cool
expects this
to be a subtype of T
which is not the case. In Bar#cool
, this
has type Bar<T extends Bar<T>>
and is a subtype of Coo<T>
but not T
.
Upvotes: 3