Java 如何检查哪个子类被传递到构造函数中?

Java 如何检查哪个子类被传递到构造函数中?,java,Java,我对Java和编程比较陌生,所以如果这个问题看起来很愚蠢,我很抱歉。我正在为一个Java编程类创建一个战斗游戏——我有一个包含一些基本方法的英雄类和一个子类Paladin,它扩展了英雄,但添加了自己独特的方法。我希望有一个战场对象可以在任何英雄类中传递,但要检查传递了哪个特定的子类。如何确定传入了哪些Hero子类 public class Hero { private String name; private int hitPoints; public Hero (String

我对Java和编程比较陌生,所以如果这个问题看起来很愚蠢,我很抱歉。我正在为一个Java编程类创建一个战斗游戏——我有一个包含一些基本方法的英雄类和一个子类Paladin,它扩展了英雄,但添加了自己独特的方法。我希望有一个战场对象可以在任何英雄类中传递,但要检查传递了哪个特定的子类。如何确定传入了哪些Hero子类

public class Hero {

  private String name;
  private int hitPoints;

  public Hero (String name, int hitPoints) {
     this.name = name;
     this.hitPoints = hitPoints;
  }

  public String getName() { return this.name; }

  public int getHitPoints() { return this.hitPoints; }

  public void takeDamage(int amount) { this.hitPoints -= amount; }
}
这是圣骑士职业

public class Paladin extends Hero {

  public Hero (String name, int hitPoints) {
    super(name, hitPoints);
  }

  public void heal(int amount) {
    this.hitPoints += amount;
  }
}
因此,在战场职业中,我有一种方法试图错误地检查通过的英雄是否是圣骑士。我该怎么做呢?if语句是一个占位符psuedo代码,只是为了澄清我的意思

public class Battleground {

  private Hero player;

  public Battleground (Hero player) {
    this.player = player;
  }

  public void startRound() {
    // HERE!!
    if (player.equals(Paladin)) {
      player.heal();
    }
  }
}
您可以始终执行player.getClass来获取实际类。至于if语句,可以使用instanceof运算符

所以

使用Instanceof有时被认为是一种代码味道 使用instanceof可以被认为是一种代码味道——这意味着一种糟糕的做法。 你可以考虑另一种选择。 将heal方法添加到Hero类,但将实现留空

在圣骑士类中只放置一个实现。然后,即使所有玩家都需要治疗,它也只能在圣骑士内部起作用

然而。。。如果仍然需要检测类类型

检测类的方法 有多种方法可以区分不同的类。 这是一个例子。 另一个是有不同的构造函数。 第三种方法是使用名为EntityType的枚举或字符串字段

在您的情况下,我认为instanceof或使用特殊字段最有意义

瞬间 使用特殊字段 速成英雄

。。。 }

快速示例圣骑士

检测类型

这两个类中都有一个名为getHeroType的方法


考虑到你的职业实际是什么,战场知道圣骑士在回合开始时会自行痊愈,或者战场负责确保圣骑士自行痊愈,这都没有多大意义

更合理的设计是让游戏通知英雄回合已经开始,并让特定的英雄子类控制该类英雄在回合开始时做什么。例如:

公众阶级英雄{ // ... 公开无效,重新开始{ //无所事事 } } 这样,您就不需要任何if语句或instanceof检查,而且定义一个圣骑士行为的代码也在圣骑士类中,它应该属于这个类。如果你以后想修改圣骑士的规则,你可以更容易地知道你需要编辑哪个职业


这种重构称为。

如果需要,可以使用检查对象的类:

如果玩家是圣骑士 毫无疑问,这会奏效的。如果你没有太多的特殊行为和有限的少量案例,这可能是一个合理的解决方案。但是假设你的游戏最终会对英雄的每个子类进行大量的特殊处理,而且可能不仅仅是在你的战地类的startrond方法中,你的代码总有一天会被这些检查的实例弄得乱七八糟。如果在Hero类中使用特定类型字段,则同样适用

在这种情况下,更好的解决方案可能是将逻辑重新定位到特殊类中,并尽可能避免类型检查,或者至少在必要时为它们定义一个良好的位置


更新:删除了错误的演示实现

player.heal将无法编译。你需要向圣骑士施放变量。或者添加一个在英雄类中不起任何作用的治疗实现,你甚至可以调用takeDamage-1*amount@cricket_007我不同意投票结果。区分类的方法不止一种。这是一个例子。另一个是有不同的构造函数。第三种方法是使用名为EntityType的枚举或字符串字段。关于后者,Joshua Bloch建议不要使用有效的Java创建自己的类型系统。您应该使用类型系统,而不是尝试引入自己的基于枚举/字符串值的getType系统@MenelaosBakopoulos@markspace的确几年前,我们曾制作过自己的类型系统,因为它被认为速度更快。我甚至记得在eclipse的AST节点中遇到过它。虽然这通常是一个很好的答案,但是BattleGroundHandler中的重载方法不太可能按照您期望的方式运行。要调用的方法在编译时根据对Hero的引用类型进行选择。例如,如果你写了英雄h=新圣骑士;然后是battlegroundHandlers.handleStartRoundh,将调用获取英雄的方法,而不是获取圣骑士的方法。你说得对,很好,谢谢。如果你想给出一个快速的答案,就会发生这种情况。不管怎样,不管具体的解决方案是什么,我想说的是 nt out是为了尽量避免代码被一堆instanceof检查或类似的检查弄得乱七八糟。
if (player instanceof Paladin) {
  ((Paladin)player).heal();
}
if(player instanceof Paladin)
 public class Hero {

      private String name;
      private int hitPoints;
      private int HeroType;

     public Hero (String name, int hitPoints) {
          this.name = name;
          this.hitPoints = hitPoints;
          this.heroType = BASIC_HERO;
      }       

      public static int BASIC_HERO = 0;
      public static int PALADIN_HERO = 1;
public class Paladin extends Hero {

public Paladin(String name, int hitPoints) {
    super(name, hitPoints);
    this.heroType = PALADIN_HERO;
  }

}
if(hero.getHeroType == Hero.PALADIN_HERO){

}else if(hero.getHeroType == Hero.BASIC_HERO){

}
public class Paladin extends Hero {
    // ...

    @Override
    public void onRoundStart() {
        // your heal method takes an int as its argument
        heal(10);
    }
}
public class Battleground {
    // ...

    public void startRound() {
        // let the particular Hero subclass control what happens
        player.onRoundStart();

        // ...
    }
}