toString和继承的问题

时间:2014-04-24 23:52:53

标签: java inheritance tostring

我无法通过toString方法找出问题。必须更改toString(),以便打印有关Player的所有相关信息(以及 项目)。子类应该覆盖超类toString(),但仍然使用toString() 从超类实现中减少代码重复。

我该怎么做?

玩家类:

import java.util.HashMap;

public class Player extends Character {

private String name;
private String type;
public static HashMap<String, Item> backpack;
private int maxCarryingCapacity;

/**Constructor
 * Creates a player with health 100, an empty backpack 
 * and max carrying capacity 100
 * 
 * @param nick the players name
 * @param type the players type
 * @param minDamage players minimum damage
 * @param maxDamage players maximum damage
 */
public Player(String name, String type, int minDamage, int maxDamage) {
    super(name, minDamage, maxDamage);
    setName(name);
    setType(type);
    health = 100; 
    gold = 100;
    backpack = new HashMap<String, Item>();
    maxCarryingCapacity = 100;
    setMinDamage(minDamage);
    setMaxDamage(maxDamage);
}

/**
 * Use an item in backpack
 * @param itemName
 * @return true if item is used, and false
 * if there's no item by that name in the backpack
 */
public boolean useItem(String itemName) {
    Item item = findItem(itemName);
    if(item != null) {
        System.out.println(name + " " + item.getAction() + " " + item.getName());
        return true;
    } else {
        return false;
    }
}

public boolean equipItem(String itemToEquip) {
    Item item = findItem(itemToEquip);
    if (item != null) {
        this.minDamage = this.minDamage + item.getBonus();
        return true;
    } else {
        return false;
    }

}

/**
 * Adds item to players inventory. An 
 * item can only be bought if the total weight does not 
 * exceed the players carrying capacity 
 * @param item
 * @return true if the item is bought
 */
public boolean addItem(Item item) {
    int totalWeight = totalWeight() + item.getWeight();
    if(totalWeight <= maxCarryingCapacity){
        backpack.put(item.getName(), item);
        return true;
    } else {
        return false;
    }
}

/**
 * Find item in backpack
 * 
 * @param name of item
 * @return item, or null if item is not int the backpack
 */
public Item findItem(String itemName) {
    return backpack.get(itemName);
}

/**
 * Removes item from player's backpack and
 * add item value to player's gold
 * 
 * @param name of item to sell
 * @return true if successful
 */
public boolean sellItem(String itemToSell) {
    Item item = findItem(itemToSell);
    if(item != null) {
        gold += item.getValue();
        backpack.remove(item.getName());
        return true;
    }  else {
        return false;
    }
}

/**
 * @return true if the player is alive
 */
public boolean isAlive() {
    if(health > 0 && health <= 100) {
        return true;
    } else return false;
}

/**
 * @return a string with player information
 */
@Override
public String toString() {
    String string = "Name: " + name + " Type: " + type + "\n";
    if(isAlive()) {
        string += "Is alive with health: " + health;
    } else {
        string += "Is dead.";
    }
    string += "\n"+ name + "'s backpack contains the following items: \n";

    for(Item item : backpack.values()) {
        string += item;
    }
    return string;
}

/**
 * @return the players type
 */
public String getType() {
    return type;
}

/**Sets the players type
 * Valid types: Mage, Ranger, Warrior, Rogue
 * @param newType
 */
public void setType(String newType) {
    newType = newType.toLowerCase().trim();
    if(newType.equals("mage") || newType.equals("ranger") || newType.equals("warrior") || newType.equals("rogue")){
        this.type = newType;
    } else {
        this.type = "Unspecified";
    }
}

/**
 * @param item
 * @return current carrying weight
 */
private int totalWeight() {
    int tempWeight = 0;
    for(Item itemInBackpack : backpack.values()) {
        tempWeight += itemInBackpack.getWeight();
    }
    return tempWeight;
}

public int attack(Monster currentEnemy) {
    int damage = Utils.random(minDamage, maxDamage+1);
    currentEnemy.changeHealth(-damage);
    return damage;
}

}

Character超类(抽象类):

abstract class Character
{
public String name;
public static int health;
public int gold;
public int minDamage;
public int maxDamage;


public Character(String name, int minDamage, int maxDamage) {
    setName(name);
    health = 100;
    gold = 100;
    setMinDamage(minDamage);
    setMaxDamage(maxDamage);
}

public Character () {

}

/**
 * Changes the character health
 * The health can not be less the 0 or "less than or euqal to" 100.
 * @param healthPoints
 */
public void changeHealth(int healthPoints) {
    int temp = health + healthPoints;
    if(temp > 100) {
        health = 100;
    } else if (temp <= 0) {
        health = 0;
    } else {
        health = temp;
    }
}

    /**
 * @return true if the character is alive
 */
public boolean isDead() {
    if(health > 0 && health <= 100) {
        return false;
    } else return true;
}

/**
 * @return the characters name
 */
public String getName() {
    return name;
}

/**Set to Unspecified if the string is empty
 * @param name
 */
public void setName(String name) {
    this.name = Utils.checkString(name);
}

 /**
 * @return the characters health
 */
public static int getHealth() {
    return health;
}

 /**
 * Get minimum damage
 * @return minimum damage
 */
public int getMinDamage() {
    return minDamage;
}

/**
 * Set minimum damage, if minDamage >= 5, minDamage is otherwise set to 5
 * @param minimum Damage
 */
public void setMinDamage(int minDamage) {
    this.minDamage = minDamage >= 5 ? minDamage : 5;
}

/**
 * Get maximum damage
 * @return maximum damage
 */
public int getMaxDamage() {
    return maxDamage;
}

/**
 * Set maximum damage, if maxDamage <= minDamage, maxDamage is set to minDamage +5
 * @param maximum damage
 */
public void setMaxDamage(int maxDamage) {
    this.maxDamage = maxDamage <= minDamage ? minDamage+5 : maxDamage;
}

/**
 * Get money
 * @return amount of money
 */
public int getGold() {
    return gold;
}

/**
 * Set money
 * @param amount of money
 */
public void setGold(int gold) {
    this.gold = Utils.checkNegativeInt(gold);
 }

}

3 个答案:

答案 0 :(得分:3)

一般来说,给定两个类AB以及类B extends A,那么B具有A的所有属性以及它自己的一些属性。因此,当您实施B的{​​{1}}方法时,您应该这样做:

toString()

但是,您的实施不会为@Override public String toString() { String newStuff = // description of the new variables return super.toString() + newStuff; // Now describe the elements of B that aren't included in A } 提供基本toString()方法,因此调用Character等同于调用super.toString()。因此,您应该首先为Object.toString()抽象类实现toString。

例如,您可以这样做:

Character

但代码中存在大量冗余。首先,您的public String toString() { return "Name: " + name + "\nHealth: " ... all the attributes } 类和Character类都具有相同的Player变量,这与继承点相反。实际上,您甚至从未使用name的名称变量。

另外,如果所有变量都被声明为公共,那么在Player中创建getter / setter方法是没有意义的。最好将它们设为私有,然后使用getter / setter。

答案 1 :(得分:1)

您的抽象超类有namehealth,但不是typebackpack。 (我刚刚注意到,感谢user2573153的答案,你name课程中也有Player;我认为你不想这样做。)

我认为您要做的第一件事就是回答这个问题:假设您创建了一个新的子类,并且不要覆盖toString(),然后打印出一个对象。你想看到什么打印出来?

也许你想要打印出名字和健康。因此,您可以在抽象的Character类中声明这一点(我认为不应该将其称为Character因为java.lang已经有Character):

@Override
public String toString() {
    String string = "Name: " + name + "\n";
    if(isAlive()) {
        string += "Is alive with health: " + health;
    } else {
        string += "Is dead.";
    }
    return string;
}

然后,如果您希望toString()Player中的Monster添加一些内容,那将非常简单:

@Override
public String toString() {
    String string = super.toString();  // here's where you call the superclass version
    string += "\n Type: " + type; 
    string += "\n"+ name + "'s backpack contains the following items: \n";

    for(Item item : backpack.values()) {
        string += item;
    }
    return string; 
}

但是,在实际代码中,您希望在超类Type返回的字符串的 middle 中插入toString()信息。这让事情变得更加艰难。我可以想到两种方法来处理它。一种方法是使用一些字符串操作方法来搜索\n并插入&#34; Type&#34;在那里的字符串。但我认为将字符串拆分为两种方法会更好。您可以将它们放在Character课程中:

protected String nameString() {
    return "Name: " + name;
}

protected String healthString() {
    if(isAlive()) {
        return "Is alive with health: " + health;
    } else {
        return "Is dead.";
    }
}

现在,toString()中的Character可能看起来像

@Override
public String toString() {
    return nameString() + "\n" + healthString();
}

Player

@Override
public String toString() {
    return nameString() + " Type: " + type + "\n" + healthString();
}

你仍然可以避免重复的代码。 (你不需要说super.nameString(),因为你的子类会自动继承它而你不打算覆盖它。)

答案 2 :(得分:0)

不会自动调用超类方法。当您在播放器中覆盖 toString()并在播放器的实例上调用 toString()时,唯一的代码运行的是播放器&#39; toString()

如果您想在播放器 toString()中加入字符 toString(),需要通过在播放器 toString()中调用 super.toString()来明确说明。

toString()播放器实施可以修改为包含我的建议如下:

/**
 * @return a string with player information
 */
@Override
public String toString() {
  String string = "Name: " + name + " Type: " + type + "\n";
  if(isAlive()) {
    string += "Is alive with health: " + health;
  } else {
    string += "Is dead.";
  }
  string += "\n"+ name + "'s backpack contains the following items: \n";

  for(Item item : backpack.values()) {
    string += item;
  }
  return super.toString() + string;
}

这一点的显着部分正在发生变化:

  return string;

要:

  return super.toString() + string;