Reputation: 69259
I had a question about similar generics yesterday, and as solution I implemented a sort of self-reference in some classes, like this:
public interface Action { }
public interface Result { }
public interface Player<A extends Action, R extends Result, P extends Player<A, R, P>> {
default public void onPostAction(final P target, final A action, final R result) { }
}
abstract public class GesturePlayer<A extends Action, R extends Result, P extends GesturePlayer<A, R, P>> implements Player<A, R, P> { }
abstract public class RPSPlayer extends GesturePlayer<RPSGesture, RPSResult, RPSPlayer> { }
public class RPSHumanPlayer extends RPSPlayer {
@Override
public void onPostAction(final RPSHumanPlayer target, final RPSGesture gesture, final RPSResult result) { }
}
This code does not compile, hoewver I am unable to figure out why.
It does work if in the @Override
I use RPSPlayer
, however RPSHumanPlayer
is simply a subclass of it, should it not work the same as the following?
List<T> list = new ArrayList<>();
Which also has the type definied as the superclass (List
resp RPSPlayer
), and the referenced object's type as the subclass (ArrayLast
resp RPSHumanPlayer
).
My aim with this question is to gather insight on how the generics exactly work, and I want to keep the method signature as it is defined in RPSHumanPlayer
.
What I think I understand about generics:
T
is a typed parameter, like List<String>
, etc. Also able to use it for own classes and methods. This also captures all subclasses of T
.?
captures all possible Object
s. Used to ensure that something is generic and not raw.? extends T
capture a specific subclass of T
.This code is written on Java 8.
Upvotes: 1
Views: 135
Reputation: 58858
Your problem boils down to this:
public interface Player {
default public void onPostAction(Player target) {}
}
public abstract class HumanPlayer implements Player {
@Override
public void onPostAction(HumanPlayer target) {}
}
This cannot work, because onPostAction(HumanPlayer)
cannot override onPostAction(Player)
, because then what would happen if it was called with a Player
that was not a HumanPlayer
?
Upvotes: 1
Reputation: 3201
In order to achieve the desired method signature in RPSHumanPlayer
, you will need to generify RPSPlayer
like this:
abstract public class RPSPlayer<P extends RPSPlayer<P>> extends GesturePlayer<RPSGesture, RPSResult, P> { }
Then you can define:
public class RPSHumanPlayer extends RPSPlayer<RPSHumanPlayer>
In Java, parameter types are part of the method signature, so they can't be changed (not even subclassed). Since Java 5, you can use covariant return types, but that's as far as it goes.
Upvotes: 2