Reputation: 43
I am having trouble using Type Arguments in Java Classes. I have one superclass named Game
public abstract class Game<T extends Player> implements Serializable {
public Game(GameEnum game, Player player1, T player2) {
this.timer = new Timer();
this.game = game;
this.player1 = player1;
this.player1.setPlayer1();
this.player2 = player2;
}
}
Then there is my Class which extends it
public abstract class OtherGame<T extends Player> extends Game<T> {
public OtherGame(GameEnum game, Player player1, T player2) {
super(game, player1, player2);
}
}
Then there is the Class ChessGame which extends the Class OtherGame
public class ChessGame<T extends Player> extends OtherGame<T> {
public ChessGame(Player player) {
super(GameEnum.CHESS, player, new ChessComputer());
//Here is the Error that the Constructor with the Param. ChessComputer
//does not exist and i can cast the ChessComputer to T.
((Computer) super.player2).setInput(this.chessboard);
this.playerFile = new File(CHESSGAME, String.format("%s vs. Computer%s", super.player1, FILEEXT));
this.comFile = new File(CHESSGAME, super.player1.hashCode() + "");
this.gameMenu();
}
}
Now I also have some PlayerClasses
public class Player implements Serializable {
public Player(String name, boolean player1) {
this.name = name;
this.player1 = player1;
}
}
And my Computerclass which extends the Playerclass
public abstract class Computer extends Player {
public Computer() {
super("Computer", false);
}
}
And I have a ChessComputerclass which extends the Computerclass
public class ChessComputer extends Computer {
public ChessComputer() {
super();
}
}
I have then a Class which calls the Constructor of the ChessGameclass as following:
new ChessGame<ChessComputer>(this.player);
//Here is no error
Why is there the Error that there is no such Constructor, because I thought if I use a TypeVariable, such as T, I could give the Constructor any Subclass of the one that I said it would Extend. I also call the ChessGame Constructor with the Typeargument ChessComputer of which I thought would "give" T the class ChessComputer. I know a little about Typearguments and how they work in Java, but obviously not enough.
I am sorry if I don't use the right Words to describe it, that's because English is not my first Language.
Upvotes: 1
Views: 161
Reputation: 43
I have a "good" Solution I would think,
I changed the Constructor of my ChessGame class
public class ChessGame<T extends Player> extends OtherGame<T> {
public ChessGame(Player player, T player2) {
super(GameEnum.CHESS, player, player2);
if (super.player2 instanceof Computer) {
((Computer) super.player2).setInput(this.chessboard);
}
this.playerFile = new File(CHESSGAME, String.format("%s vs. Computer%s", super.player1, FILEEXT));
this.comFile = new File(CHESSGAME, super.player1.hashCode() + "");
this.gameMenu();
}
}
And call the Constructor like
new ChessGame<Computer>(this.player, new ChessComputer());
I still have to cast the player but since it is a save cast there is nothing to worry about, I think.
Upvotes: 0
Reputation: 2723
Extending generic classes with other generics is problematic. It's not that your code is wrong, but the compiler can only do so much to evaluate it and java's usage of generics isn't perfect.
The best solution I've found is to try to limit the level of generic type reference to the current class, or maybe one super. Beyond that lies problems.
This resolves the issue:
public class ChessGame<T extends Player> extends OtherGame<Player>
Upvotes: 1
Reputation: 120
Here the structure of class-derived class pair has a generic type constraint:
public class ChessGame<T extends Player> extends OtherGame<T>
public ChessGame(Player player) {
super(GameEnum.CHESS, player, new ChessComputer());
OtherGame constructor's 3rd param is stricted to type T even if it is a subtype of ChessComputer. It needs cast of T like super(GameEnum.CHESS, player, (T) new ChessComputer());
On the other hand, as @jrook commented, using generic type is not well suited here if you don't have other plans. You should consider using interfaces as Player class implementing a common IPlayer interface and you can pass the sub classes to other classes' constructors.
Upvotes: 1