【问题标题】:Java only calling method with parent as its function parameterJava 仅调用以 parent 作为其函数参数的方法
【发布时间】:2021-03-11 20:37:00
【问题描述】:

在我的项目中,我遇到了这个问题,我有一个实体的抽象类,它的子类是 Player、Shot 和 Enemy。我想检查它们之间的碰撞。一个单独的物理类正在使用以下代码进行碰撞评估:

public class Physics {

    private static int height = 32;
    private static int width = 32;

    public static void collision(Entity entity, LinkedList<Entity> eList) {
        for (int i = 0; i<eList.size(); i++) {
            if (entity.getBounds(width, height).intersects(eList.get(i).getBounds(width, height))) {
               entity.collidesWith(eList.get(i));
             }
         }
     }
}

linkedList 包含 Shots 和 Enemies,但由于某种原因,碰撞仅调用 collidesWith(Entity entity) 方法,而不是 collidesWith(Shot b) 或 collidesWith(Enemy e)。

编辑:提到的类(在这种情况下,只有我认为对它们很重要的代码)

实体:

public abstract class Entity {

protected double x;
protected double y;

public Entity (double x, double y) {
    this.x = x;
    this.y = y;
}

public abstract void tick();

public double getX() { return x; }
public double getY() { return y; }

public Rectangle getBounds(int width, int height) {
    return new Rectangle((int)x, (int)y, width, height);
}

public abstract void collidesWith(Entity e);
public abstract void collidesWith(Enemy e);
public abstract void collidesWith(Shot s);

玩家:

   public class Player extends Entity {

private boolean alive;

private int gameWidth, gameHeight;
private GameController gCont;
private Textures textures;

public Player( String name, int x, int y, int gameWidth, int gameHeight, Textures textures, GameController gCont) {
    super(x,y);
    this.name = name;
    this.score = 0;
    this.gameWidth = gameWidth;
    this.gameHeight = gameHeight;
    this.gCont = gCont;
    this.textures = textures;
    this.alive = true;
}

public void tick() {        
    gCont.collisionCheck(this);
}

public void collidesWith(Enemy e) {
    System.out.println("Player collides with enemy");
    this.alive = false;
}
public void collidesWith(Shot s) {
    return;
}

public void collidesWith(Entity e) {
    System.out.println("collided with entity");
    return;
}

射击

    public class Shot extends Entity {

private Textures textures;
private GameController gCont;

public Shot(double x, double y, Textures textures, GameController gCont) {
    super(x, y);
    this.textures = textures;
    this.gCont = gCont;
}

public void tick() {
    x+=10;
    gCont.collisionCheck(this);
    
}

public void collidesWith(Entity e) {
    return;
}

public void collidesWith(Enemy e) {
    gCont.removeEntity(e);
    gCont.removeEntity(this);
    gCont.addScore();
}

@Override
public void collidesWith(Shot s) {
    return;     
}

敌人

public class Enemy extends Entity {
private int speed;

public Enemy(double x, double y) {
    super(x, y);
    Random random = new Random();       
    speed = random.nextInt(3)+1;
}

public void tick() {
    x-=speed;
}

public void collidesWith(Entity e) {
    return;
}

@Override
public void collidesWith(Enemy e) {
    return;
    
}

@Override
public void collidesWith(Shot s) {
    return;     
}

如何让它调用正确的函数?

【问题讨论】:

  • 请提供您提到的每个类的声明。

标签: java function call parent abstract


【解决方案1】:

查看 Java 的泛型。我认为你可以使用这样的东西:

public abstract class Entity<T> {

    protected double x;
    protected double y;

    public Entity (double x, double y) {
        this.x = x;
        this.y = y;
    }

    public abstract void tick();

    public double getX() { return x; }
    public double getY() { return y; }

    public Rectangle getBounds(int width, int height) {
        return new Rectangle((int)x, (int)y, width, height);
    }

    public abstract void collidesWith(T e);
}

【讨论】:

    【解决方案2】:

    可能是错的,我是新来回答有关 stackoverflow 的问题。

    希望这能让你更清楚:

    entity.collidesWith(eList.get(i));

    eList.get(i) 在该行中,在您的物理类 Entity 中返回一个实体类型的对象。 这是因为它是这样定义的:

    LinkedList&lt;Entity&gt; eList

    这意味着如果您有一个采用该实体的重载,它只会调用该方法。这正是我在您的代码中看到的。您有一个带有参数的“collidesWith”方法重载:实体。 在 Entity 的所有子类中。

    我认为您应该阅读更多关于“Java 多态性”的内容。

    【讨论】:

    • 我喜欢这个解决方案,但我会使用我在答案中指定的界面。 +1 岁
    • 谢谢。我的目标不是解决他的问题,就像您的综合回答一样。主要指出为什么代码只执行这些方法。
    • @OminousApple 真的很感谢到目前为止的所有答案 ^^ 多态性是我的第一个想法,每个类只有 collidesWith(),具有不同的参数类(例如 collidesWith(Shot s)、collidesWIth(Enemy e ))。但我还必须拥有基本的 collidesWIth(Entity e),因为它是一个抽象函数,我认为它对于物理学中的循环是必要的。结果是在每个类中只调用了 cW(Entity e),而不是具有匹配参数类型的类。我能用它做什么?
    • 让我这样说。碰撞的对象将始终具有实体的基本类型。 (在当前情况下,我可以在代码中看到)您不需要其他方法重载。因为`collidesWith(Entity e)`将处理所有这些。因此,您将在 collidesWith(Entity e) 中处理您的对象 Shot。您必须弄清楚如何检查实体 e 是否为 Shot,Player,Bullet(派生自实体的特定类型)。一个肮脏的检查方法是在该方法中使用 instanceOf。
    【解决方案3】:

    对我来说,知道 Enemy 和 Shot 的 Entity 类是错误的。

    为什么不把这两个方法从Entity和子类中去掉:

    public abstract void collidesWith(Enemy e);
    public abstract void collidesWith(Shot s);
    

    并且只保留和执行:

    public abstract void collidesWith(Entity e);
    

    如果您需要知道作为参数传递的 Entity e 的类型,可以使用反射,但这是不好的设计。最好以不需要知道传递参数的确切类型的方式实现 collidesWith

    【讨论】:

      【解决方案4】:

      我认为除了 Jamie Bisotti 指定的通用类型之外的解决方案是使用接口和开关来检查哪个类是什么。
      这是声明所有可以碰撞的实体都必须具有的方法的接口:

      public interface Collidable {
          public boolean collidesWith(Collidable entity);
      }
      

      那么你希望能够碰撞的每个类都必须实现:

      public class Enemy extends Entity implements Collidable {
      private int speed;
      
      public Enemy(double x, double y) {
          super(x, y);
          Random random = new Random();       
          speed = random.nextInt(3)+1;
      }
      
      public void tick() {
          x-=speed;
      }
      
      @Override
      public void collidesWith(Collidable e) {
      
          if (e.getClass().equals(Shot.class)) {
              // DO SOMETHING, I am colliding with a shot
          } else if(e.getClass().equals(Enemy.class)) {
              // I am colliding with an Enemy
          }
      
          . . . etc
      }
      
      

      我更喜欢使用接口,因此我可以指定每种行为。目前看起来一切都很简单,一切都可以从 Entity 抽象类扩展,但总有一天你会通过许多其他特性来区分每个实体。
      例如飞行的敌人,行走的敌人,ecc ecc,您可以使用界面指定每个功能。

      在这种情况下,界面也很简单。但是您可以指定许多要实现的方法,例如

      public boolean canCollide();
      public boolean isAlive(); //if the entity is already dead you might want not to stop a bullet
      public boolean isAnimatingDeath(); //if the entity is animating death could collide with another antity because of its exploding animation, maybe you want to avoid that.
      

      您可以在抽象实体类中实现 som 方法,但该抽象实体不应该知道它的子实体。这就是直接在子级中使用通用“可碰撞”类型作为输入来实现某些方法的原因。

      【讨论】:

      • 感谢您的回答!可悲的是,我担心它现在对我不起作用。这与我几个小时前的做法类似,但在与我的前辈讨论后,他说这不是一个正确的 OOP 方式,因为“if”中的类型检查- s。我知道在我给出的示例代码中也很不正确,但那是我的代码的当前状态,我想知道从这里去哪里。
      猜你喜欢
      • 2016-06-09
      • 1970-01-01
      • 2013-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多