如何在 Java 中创建对象的 ArrayList 并能够访问它们的值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12022913/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 07:19:19  来源:igfitidea点击:

How to make an ArrayList of objects in Java with the ability to access their values

javaclassobjectarraylist

提问by Jeremy Sayers

so I'm working on a game in Java, and I'm a little confussed on how I should go about something. It's a Trading Card Game, kinda like Magic, and so for classes so far I have

所以我正在用 Java 开发一个游戏,我对如何去做一些事情感到有些困惑。这是一个集换式卡牌游戏,有点像万智牌,所以到目前为止我有

  • GameDriver
  • Cards
  • WolfCard
  • TheLarionCard
  • 游戏驱动
  • 狼牌
  • 拉里昂卡

It is my hope that I'll be able to have atleast 50 different types of card, each of which in their own class, so a little side question is, is this the best way? As for my problem:

我希望我能够拥有至少 50 种不同类型的卡片,每一种都在自己的班级中,所以一个小问题是,这是最好的方法吗?至于我的问题:

I have the following code inside my GameDriver class:

我的 GameDriver 类中有以下代码:

ArrayList<Cards>  playerHand = new ArrayList<Cards>();
playerHand.add(new WolfCard());
playerHand.add(new TheLarionCard());
System.out.println(((Cards)playerHand.get(1)));

Each card extends Cards, and Cards extend GameDriver, The code above will print out something like:

每张卡片都扩展了 Cards,而 Cards 扩展了 GameDriver,上面的代码会打印出类似的内容:

TheLarionCard[panel0,0,0,0x0,invalid,layout=java.awt.FlowLayout]

But now, if I want to grab the health of say TheLarionCard, I thought I could just add .health to the last line like:

但是现在,如果我想获取 TheLarionCard 的健康状况,我想我可以将 .health 添加到最后一行,例如:

System.out.println(((Cards)playerHand.get(1).health));

But obviously I can't, what am I doing wrong here?

但显然我不能,我在这里做错了什么?

Any help is great! Thank you!

任何帮助都很棒!谢谢!

采纳答案by chm

I think you have three options:

我认为你有三个选择:

  1. You want each different type of card to have a healthproperty. In this case, you can put that property into the parent class Cardsand then it will be valid to ask for the property for any class that extends Cards. If the Cardsclass has a healthdata field, the code in your question will work.

  2. You want only TheLarionCardto have a health property. In that case, your cast would have be:

    System.out.println(((TheLarionCard)playerHand.get(1).health));
    

    This way, the compiler has knows to look in the TheLarionCardclass for the health property, not the Cardsclass.

  3. You don't actually need the individual card classes to be subclasses of Cards. If there's no really compelling reason you've done it that way, you could have all cards be part of the Cardsclass and their different types (TheLarionCard, WolfCard, etc) could be designated by a data field. For example:

    public class Card {
        String type;
    
        public Card(String inType) {
            this.type = inType;
        }
    
        public String toString() {
            return "This is a " + type;
        }
    }
    

    This way if you want the different cards to behave differently, you can check their typevalue and assign different behaviors based on its value, e.g.

    public void awesomeMethod() {
        if ("TheLarionCard".equals(type)) {
            // execute TheLarionCard code
        } else if ("WolfCard".equals(type)) {
            // execute WolfCard code
        }
    }
    

    This is a simplified version of the Abstract Factory Patterndesign that some of the other answers were talking about, so if you're new to interfaces you could try it this way to see if the structure works, then add interfaces later.

  1. 您希望每种不同类型的卡都有一个health属性。在这种情况下,您可以将该属性放入父类Cards,然后为任何扩展Cards. 如果Cards该类具有health数据字段,则问题中的代码将起作用。

  2. 您只想TheLarionCard拥有健康属性。在这种情况下,您的演员阵容将是:

    System.out.println(((TheLarionCard)playerHand.get(1).health));
    

    这样,编译器就知道在TheLarionCard类中查找 health 属性,而不是Cards类。

  3. 您实际上并不需要将单个卡片类作为Cards. 如果没有真正令人信服的理由这样做,您可以让所有卡片都成为Cards类的一部分,并且它们的不同类型(TheLarionCard、WolfCard 等)可以由数据字段指定。例如:

    public class Card {
        String type;
    
        public Card(String inType) {
            this.type = inType;
        }
    
        public String toString() {
            return "This is a " + type;
        }
    }
    

    这样,如果您希望不同的卡片表现不同,您可以检查它们的type值并根据其值分配不同的行为,例如

    public void awesomeMethod() {
        if ("TheLarionCard".equals(type)) {
            // execute TheLarionCard code
        } else if ("WolfCard".equals(type)) {
            // execute WolfCard code
        }
    }
    

    这是其他一些答案所讨论的抽象工厂模式设计的简化版本,因此如果您不熟悉接口,您可以尝试这种方式,看看结构是否有效,然后再添加接口。

回答by Jo?o Silva

Define an interface or abstract method getHealth()method in Cards, that must be implemented by WolfCardand TheLarionCard. Then, you can do playerHand.get(1).getHealth().

在 中定义接口或抽象方法getHealth()方法Cards,必须由WolfCard和实现TheLarionCard。然后,你可以做playerHand.get(1).getHealth()

For instance:

例如:

public abstract class BaseCard {
  protected int health;

  public abstract int getHealth();
}

public class WolfCard extends BaseCard {
  private int wolfHealthBoost;  

  public int getHealth() {
    return health + wolfHealthBoost;
  }
}

public class TheLarionCard extends BaseCard {
  public int getHealth() {
    return health;
  }
}

回答by Rolobster

You should check if you have the getter for the health attribute in those classes, private attributes can't be accessed from outside the class.

您应该检查这些类中是否有 health 属性的 getter,不能从类外部访问私有属性。

Just make a new method, getHealth(), that returns the health attribute, and then append it after the dot at the last line.

只需创建一个新方法 getHealth(),它返回 health 属性,然后将其附加在最后一行的点之后。

BTW, you don't have to cast the Cards class if you already defined the ArrayList with that stereotype.

顺便说一句,如果您已经使用该构造型定义了 ArrayList,则不必强制转换 Cards 类。

回答by Shivan Dragon

You don't really need interfaces or even such a complex variety of classes. I'm guessing all of your Cards have generally similar behavior. They are of a certain type, can do a specific action, can have actions and/or effects happen onto them etc. So you only need one Cards class for this, and in it have all the fields and methods that manage those generic states/actions.

您实际上并不需要接口,甚至不需要如此复杂的各种类。我猜你所有的卡片都有大致相似的行为。它们属于某种类型,可以执行特定操作,可以对它们执行操作和/或效果等。因此,您只需要一个 Cards 类,其中包含管理这些通用状态的所有字段和方法/行动。

Then you can make separate classes that inherit from Cards class (which btw, it's better to rename to just "Card"), like if you have effect type cards (such as a MTG Mana Flare or Hideous Visage equivalents) and then you also have creature cards (like MTG's Shivan Dragon or Dragon Whelp) you can make classes such as EffectCard which might have it's own fields like "duration" and "affectedTypes" and then use it to make ManFlare instances, Hideous Visage instances, etc. Also make a CreatureCard with stuff like hitpoints, firstStrike, etc. and make ShivanDragon instances and DragonWhelp instances from it.

然后,您可以创建从 Cards 类继承的单独类(顺便说一句,最好重命名为“Card”),例如如果您有效果类型的卡片(例如 MTG Mana Flare 或 Hideous Visage 等价物),那么您还有生物卡(例如 MTG 的 Shivan Dragon 或 Dragon Whelp),您可以制作诸如 EffectCard 之类的类,这些类可能具有自己的字段,例如“duration”和“affectedTypes”,然后使用它来制作 ManFlare 实例、Hideeous Visage 实例等。还可以制作一个CreatureCard 包含生命值、firstStrike 等内容,并从中制作 ShivanDragon 实例和 DragonWhelp 实例。

Also don't be afraid of composition. Instead of subclassing/making extra classes for each card, make a simpler hierarchy like the one above and pass it "command" or "action" classes which dictates the more specific details. Like the FirstStrike instance of the EffectCard class could be initialized with an "action" instance that tells it specifically how to affect a CreatureCard instance, the ShivanDragon instance of the CreatureCard class would have an action telling it how it's attack can be increased by utilizing Red Lands cards, etc.

也不要害怕作文。不是为每张卡片子类化/创建额外的类,而是创建一个更简单的层次结构,如上面的层次结构,并将其传递给“命令”或“动作”类,这些类指示更具体的细节。就像 EffectCard 类的 FirstStrike 实例可以用一个“动作”实例初始化,具体告诉它如何影响 CreatureCard 实例,CreatureCard 类的 ShivanDragon 实例将有一个动作,告诉它如何通过使用 Red 来增加攻击地牌等