Java 循环泛型(尝试2)
第二次尝试提问(初始代码不足以突出问题) 以下是未编译的代码:Java 循环泛型(尝试2),java,generics,Java,Generics,第二次尝试提问(初始代码不足以突出问题) 以下是未编译的代码: interface Player<R, G extends Game> { R takeTurn(G game); } interface Game<P extends Player> { void play(P player); } abstract class AbstractGame<R, P extends Player> implements Game<
interface Player<R, G extends Game>
{
R takeTurn(G game);
}
interface Game<P extends Player>
{
void play(P player);
}
abstract class AbstractGame<R, P extends Player>
implements Game<P>
{
public final void play(final P player)
{
final R value;
value = player.takeTurn(this);
turnTaken(value);
}
protected abstract void turnTaken(R value);
}
public class XPlayer
implements Player<Integer, XGame>
{
@Override
public Integer takeTurn(final XGame game)
{
return (42);
}
}
public class XGame<P extends Player<Integer, XGame>>
extends AbstractGame<Integer, XPlayer>
{
@Override
protected void turnTaken(final Integer value)
{
System.out.println("value = " + value);
}
}
public class Main
{
public static void main(final String[] argv)
{
final XPlayer player;
final XGame game;
player = new XPlayer();
game = new XGame();
game.play(player);
}
}
界面播放器
{
R轮流(G博弈);
}
界面游戏
{
无效游戏(P玩家);
}
抽象类抽象游戏
执行游戏
{
公开决赛无效赛(决赛P玩家)
{
最终R值;
value=player.takeTurn(这个);
营业额(价值);
}
受保护的抽象无效值(R值);
}
公共类XPlayer
机具播放机
{
@凌驾
公共整数轮流(最终XGame游戏)
{
返回(42);
}
}
公共类XGame
扩展抽象游戏
{
@凌驾
受保护的无效值(最终整数值)
{
System.out.println(“value=“+value”);
}
}
公共班机
{
公共静态void main(最终字符串[]argv)
{
最后一名球员;
决赛;
player=新的XPlayer();
game=新XGame();
游戏。玩(玩家);
}
}
我遇到的是试图编译AbstractGame中的play方法。似乎我不得不在游戏中绕圈子,玩家在扩展/实现中添加泛型,但就我的一生而言,我无法做到这一点
在AbstractGame类中,play方法必须是最终的,而且没有办法进行铸造,如果不需要的话,我不想编写另一个像Turntake这样的方法来让它工作
编辑:根据要求,这里是编译的代码,但需要强制转换:
interface Player<R, P extends Player<R, P, G>, G extends Game<R, G, P>>
{
R takeTurn(G game);
}
interface Game<R, G extends Game<R, G, P>, P extends Player<R, P, G>>
{
void play(P player);
}
abstract class AbstractGame<R, G extends Game<R, G, P>, P extends Player<R, P, G>>
implements Game<R, G, P>
{
public final void play(final P player)
{
final R value;
value = player.takeTurn((G)this);
turnTaken(value);
}
protected abstract void turnTaken(R value);
}
class XPlayer
implements Player<Integer, XPlayer, XGame>
{
@Override
public Integer takeTurn(final XGame game)
{
return (42);
}
}
class XGame
extends AbstractGame<Integer, XGame, XPlayer>
{
@Override
protected void turnTaken(final Integer value)
{
System.out.println("value = " + value);
}
}
class Main
{
public static void main(final String[] argv)
{
final XPlayer player;
final XGame game;
player = new XPlayer();
game = new XGame();
game.play(player);
}
}
界面播放器
{
R轮流(G博弈);
}
界面游戏
{
无效游戏(P玩家);
}
抽象类抽象游戏
实施游戏
{
公开决赛无效赛(决赛P玩家)
{
最终R值;
value=player.takeTurn((G)this);
营业额(价值);
}
受保护的抽象无效值(R值);
}
类XPlayer
机具播放机
{
@凌驾
公共整数轮流(最终XGame游戏)
{
返回(42);
}
}
类游戏
扩展抽象游戏
{
@凌驾
受保护的无效值(最终整数值)
{
System.out.println(“value=“+value”);
}
}
班长
{
公共静态void main(最终字符串[]argv)
{
最后一名球员;
决赛;
player=新的XPlayer();
game=新XGame();
游戏。玩(玩家);
}
}
混合泛型和原始类型是行不通的。如果需要这些接口相互引用,它们还需要引用自身:
interface Player<R, P extends Player<R, P, G>, G extends Game<R, G, P>>
{
R takeTurn(G game);
}
interface Game<R, G extends Game<R, G, P>, P extends Player<R, P, G>>
{
void play(P player);
}
然而,我不能用XGame
和XPlayer
完全关闭电路:
public class XGame
extends AbstractGame<Integer, XPlayer> //compile error on XPlayer
{
protected void turnTaken(Integer value) { }
}
public class XPlayer
implements Player<Integer, XPlayer, XGame> //compile error on XGame
{
@Override
public Integer takeTurn(final XGame game)
{
return (42);
}
}
这里的关键是在AbstractGame
中声明一个抽象方法self()
,该方法返回类型为G
的实例。扩展类必须用自己的类型解析继承的类型参数,并实现self()
以返回this
。这只适用于内部代码,因为扩展类很容易存在,例如:
public class EvilGame extends AbstractGame<Integer, AnotherGame> { ... }
公共类游戏扩展了AbstractGame{…}
请参阅我的答案和有关此模式的更多详细信息。正如Paul Bellora指出的,您正在混合泛型和原始类型——正确的、完全泛型的解决方案有点混乱,需要大量冗余。据我所知,在Java中没有很好的方法来实现循环(但不是递归)泛型 与其为此而挣扎,我将使
Player
和Game
仅在一个参数上通用,即所使用的值的类型——即R
interface Game<R> {
void play(Player<? extends R> player);
}
interface Player<R> {
R takeTurn(Game<? super R> game);
}
abstract class AbstractGame<R> implements Game<R> {
public final void play(Player<? extends R> player) {
final R value;
value = player.takeTurn(this);
turnTaken(value);
}
protected abstract void turnTaken(R value);
}
class XPlayer implements Player<Integer> {
@Override
public Integer takeTurn(Game<? super Integer> game) {
return 42;
}
}
class XGame extends AbstractGame<Integer> {
@Override
public void turnTaken(Integer value) {
System.out.println("value = " + value);
}
}
public class Main {
public static void main(String[] argv) {
XPlayer player = new XPlayer();
XGame game = new XGame();
game.play(player);
}
}
界面游戏{
void play(玩家让我知道它是如何工作的-我只是修正了一些拼写错误,以防你已经复制了代码。几乎完美…唯一的问题是我必须做:value=player.takeTurn((G)this);嗯,在我的尝试中,我从不需要进行这种转换。相反,我遇到了上述问题。你能用你的新代码更新你的问题吗?我们的AbstractGame
类之间的区别在于,我的类用自己的类型解析继承的类型参数G
,这就是为什么它不需要从中进行转换
到Player
中的G
。你的G
,因此它仍然是一个变量。无论哪种方式,我建议按照的思路重新设计,就像这是尝试和工作一样有趣。另一个答案不符合要求(请参阅我对他的答案的评论)。如果有更好的地方,我可以重新设计(我想不出任何既能保证类型安全又能让大部分工作在抽象类中进行的东西)。我知道原始和泛型的混合是行不通的——我只是把代码留在了我最担心的地方:-)问题是,在真实的系统中,玩家和游戏都需要知道特定的类型,而施法并不是一个有用的解决方案,因为施法的位置在通用的层次结构中处于较高的位置(没有没有不必要的双关语)代码。另一个选择是,我会看看我是否能工作,但我认为这将是一个大的重新设计…+1真正的答案是更好的设计,正如你的答案所试图达到的。在我的例子中,我只是想看看这个难题是否真的可以编译。啊,但我不想让XPlayers玩同样使用整数作为返回值的YGame。想想看两种猜谜游戏中,每种游戏都使用整数,但玩的完全不同。这就像是一个网球选手试图玩高尔夫,因为他们都使用一个球。另外,takeTurn方法需要游戏的具体细节,只是游戏使用整数还不够好。@Toubeer一个网球和一个高尔夫球是不同的是,实际上就像一个玩家在台球桌上玩8球,另一个玩9球,这取决于你是否想在编译时阻止它,或者你是否
public class EvilGame extends AbstractGame<Integer, AnotherGame> { ... }
interface Game<R> {
void play(Player<? extends R> player);
}
interface Player<R> {
R takeTurn(Game<? super R> game);
}
abstract class AbstractGame<R> implements Game<R> {
public final void play(Player<? extends R> player) {
final R value;
value = player.takeTurn(this);
turnTaken(value);
}
protected abstract void turnTaken(R value);
}
class XPlayer implements Player<Integer> {
@Override
public Integer takeTurn(Game<? super Integer> game) {
return 42;
}
}
class XGame extends AbstractGame<Integer> {
@Override
public void turnTaken(Integer value) {
System.out.println("value = " + value);
}
}
public class Main {
public static void main(String[] argv) {
XPlayer player = new XPlayer();
XGame game = new XGame();
game.play(player);
}
}