【问题标题】:cannot reference game before super constructor has been called在调用超级构造函数之前无法引用游戏
【发布时间】:2015-01-06 19:00:00
【问题描述】:

所以我有一个超类 Ghost,在构造函数中有一个来自另一个类 Pacman 的参数。现在为了创建 4 种不同类型的幽灵(如果你喜欢吃 pacman,那就是兰迪、傻、特蕾西和苏),它们有很多相似之处,我正在制作 Ghost 的子类。在构造函数中,我从标题中得到错误。
Ghost.class的部分代码:

public class Ghost extends Actor
{
    protected Pacman game;
    Randy randy;
    Ghost pinky;    //totally unsure, but not a matter of question
    public Ghost(Pacman game)
    {
        this.game = game;

这是 Randy 的子类:

private class Randy extends Ghost {

   Actor randy;

   public Randy(){
       super(game); //here is the error
       randy = new Actor();
       this.game = game;

这就是我这样做的原因:

public void act()
    {
        if (pinky instanceof Randy){
            moveRandom();     // Randy must move ONLY randomly unlike the other ghosts
    } 

    setSlowDown(2);

    code left out here

注意代码是零散的。
最后,我问这个问题,因为我还没有找到动态变量的解决方案。欢迎所有建议。

【问题讨论】:

  • 你为什么要在自己内部存储每个类的实例? Randy 和其他 Ghosts 的实例不应该是 Pacman 游戏类中的类字段吗?为什么你首先需要传递一个 Pacman 实例来创建你的 Actor?
  • 为什么你的Ghost 类有实例变量randypinky,两者都是Ghost 类型或子类型?这似乎没有多大意义。
  • 你能告诉我们Actor构造函数吗?还有什么是PacmanGhost 是否需要持有对 Pacman 的引用?
  • @JohnBollinger 是的,当我现在考虑这个时。在 Actor 类上,它来自 JGameGrid 库。是的,我认为它必须如此。

标签: java inheritance constructor super


【解决方案1】:

首先,我要摆脱对 Randy 的双重定义。 "Randy" 用作Ghost 的成员,也用作类型。如果“Randy”是一种 Ghost(每个 Randy 都是 Ghost),则将 Ghost 抽象化并使用子类。如果“Randy”是“MovementStrategy”,则创建一个新的MovementStrategy 接口和一个Randy 实现(然后在Ghost 内部进行设置。

任何时候一个幽灵都不应该有两种或两种以上的移动策略;因为,Ghost 有一个它没有使用的移动策略,这是很糟糕的,完全不受欢迎。

这也将避免需要执行“instanceof”来控制您的逻辑,出于多种原因您确实不应该这样做。如果MovementStrategy 返回“下一个方向”,则依靠多态让“Randy”实例返回下一个方向。 “Instanceof”很好地表明您正在将与数据类型相关的代码放在数据类型之外,这是反面向对象的编程。

一般来说,最好使用一种语言的设计选择而不是反对该语言的设计选择,所以不要立即在 Java 中采用非面向对象的技术,直到有一个非常 非常这样做的令人信服的理由。

--- 编辑以显示一些代码作为插图---

public Ghost extends Actor {

  private Game game;

  private MovementStrategy strategy;

  private Location location;

  public Ghost(Game game, MovementStrategy strategy) {
    this.game = game;
    this.movementStrategy = strategy;
  }

  // From Actor, I guess
  @Override
  public void act() {
    if (location == null) {
      location = game.addGhost(this);
    }
    move(movementStrategy.getDirection(game, location));
  }

  private void move(Direction direction) {
    location = game.move(this, direction);
  }

}

public interface MovementStrategy {

  public Direction getDirection(Game game, Location location);

}

public class Randy implements MovementStrategy {

  public Direction getDirection(Game game, Location location) {
    return selectRandom(game.getPermittedDirections());
  }

}

// constructing a Ghost with a Randy movement strategy

Game game = new Game();
Ghost ghost = new Ghost(game, new Randy());

【讨论】:

  • 添加了一些代码来说明这一点。代码并不完美,但它是一个起点。
  • If "Randy" is a type of Ghost (every Randy is a Ghost) 这正是我想要创建的。
  • “Randy”在这里是一种移动策略,假设你的幽灵类型之间的唯一区别是它们的移动方式。如果这不是真的,那么您仍然可以对您的特定幽灵进行子类化并覆盖相关方法。
【解决方案2】:

你需要将游戏作为参数传递给Randy的构造函数。

【讨论】:

  • 为什么会被否决?当游戏本身没有传递给您的子类构造函数时,您不能使用“游戏”调用超级构造函数。
  • 这不是唯一的问题。如果你确实传入了它,如果你要实例化 Randy 类会发生什么?
  • @Makoto 嗯?你是什​​么意思“会发生什么”?您只需执行 new Randy(game) ... 就会创建一个新实例。
  • 不过感觉这个问题没那么简单。可能还有更多。
  • @user4425098 堆栈溢出是另一个问题。问另一个问题,也许?显示足够的代码来重现和你得到的实际异常的回溯。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多