多类型自定义arraylist

Posted

技术标签:

【中文标题】多类型自定义arraylist【英文标题】:Multiple type custom arraylist 【发布时间】:2015-09-30 12:47:03 【问题描述】:

我目前正在尝试制作一个简单的 RPG 式游戏。我希望怪物在地图上随机生成。我已经设置好了,所以当我想要一个生成它时,它会被添加到一个名为 monstersArrayList 中。当我完成时,我将拥有许多不同类型的monsters,并且每个都有自己的类(例如 Zombie、Ghost...)每个类都有一个绘制怪物的方法,称为 draw。我想知道我该怎么做。

Monsters 是一个ArrayList<Object>,因此它可以包含不同的类,但它不会让我这样做Monsters.get(i).draw();这真的可能吗,还是我很愚蠢。

【问题讨论】:

创建一个名为Monster 的接口,使用每个 怪物类型应具有的每个方法,然后将您的列表声明为List<Monster> monsters 它是一个类型化的 ArrayList 吗? Monster 类是否共享一个带有 draw 方法的基础 Monster 类? 如果你发布一些你的实际代码,即使它不能正常工作,也会很有帮助。 @Tom:不是 OP 写的(我在编辑 cmets 中解释过)。它被编辑了。所以我把它拿出来,以免给那些阅读 OP 以这种方式编码的问题的人留下错误的印象。我们实际上并不知道 OP 的代码是什么样的。 @Tom:啊,我明白你现在在说什么了。过失!我把它回滚了。 【参考方案1】:

您未能将对象ArrayList<Object> 投射回怪物

// Monster.get(i)            == Object
// (Monster) Monsters.get(i) == Monster

// cast the list item i from Object to Monster
((Monster) Monsters.get(i)).draw();

更好的解决方案:

interface Monster 
   void draw();


// implement draw on each
class Zombie implements Monster 
class Ghost implements Monster 

ArrayList<Monster> monsters = new ArrayList<>();
// legal
monsters.add(new Zombie());
monsters.add(new Ghost());

// legal
monsters.get(i).draw();

您可以使用类 -> 扩展解决方案或此接口 -> 实现。无论哪种方式,这都是实现怪物的更好方法的一个非常简单的示例。

【讨论】:

在不需要类型转换的情况下使用接口要好得多 “您未能将对象拆箱” 这里的“拆箱”是正确的词吗? “cast”不是更正确吗,因为“unbox”更有可能将原始类型拆箱/装箱为其包装器类型? @Tom 是的,我修改了它【参考方案2】:

是的,有可能,首先你需要创建一个接口,比如IMonster,其中包含一个draw 方法。然后,让每个怪物类型实现这个接口。

您的ArrayList 将如下所示:

List<IMonster> monsters = new ArrayList<IMonster>();

monsters.add(new Ghost());
monsters.add(new Goblin());

所以这里是一个例子:

import java.util.ArrayList;
import java.util.List;

public class Monsters 
    private static List<IMonster> monsters = new ArrayList<IMonster>();

    public static void main(String[] args) 
        monsters.add(new Ghost());
        monsters.add(new Goblin());
        monsters.add(new Devil());  

        for (IMonster monster : monsters) 
            monster.draw();
        
    


interface IMonster 
    public void draw();


abstract class AbstractMonster implements IMonster 
    @Override
    public void draw() 
        System.out.println("Shared drawing code for all monsters");
     


class Ghost extends AbstractMonster 
    @Override
    public void draw() 
        super.draw();
        System.out.println("Ghost drawing code");
    


class Goblin extends AbstractMonster 
    @Override
    public void draw() 
        super.draw();
        System.out.println("Goblin drawing code");
    


class Devil extends AbstractMonster 
    @Override
    public void draw() 
        super.draw();
        System.out.println("Devil drawing code");
    

【讨论】:

不要忘记在你的语句中实际有一个变量名。 :) 并尝试始终将接口用于变量类型,因此List&lt;IMonster&gt; 而不是ArrayList&lt;IMonster&gt; 如果有共同的绘图代码,每个子类型可能决定先调用其超类的draw方法。子类型也可以选择完全自己绘制,在这种情况下你根本不调用 super.draw()... @Constantin 请注意,我已将缺少的注释 @Override 添加到您的 draw 实现中。这样做总是一个很好的主意来启用编译器检查。如果您不喜欢它们,那么您或我都可以删除它们。顺便说一句:您可能需要重新考虑 new("Ghost"),因为这不是有效的 Java 代码:P。 谢谢汤姆,我改了。我运行了代码,它似乎可以工作【参考方案3】:

你必须像这样从 ArrayList 中转换你的项目 -

Object item = Monsters.get(i);
Monster monster = (Monster) item;
monster.draw();  

或者更好的是你可以使用一些接口。您可以使用接口(例如 Drawable )。您的 Monster 和其他可绘制类将实现它。然后使用DrawableArrayList

interface Drawable
   public void draw();
 

public class Monster implements Drawable 

   public void draw()
      //implementation of monster's draw
    
 
...
... 

ArrayList<Drawable> monsters = new ArrayList<Drawable>();
...
...
monsters.get(i).draw();

【讨论】:

以上是关于多类型自定义arraylist的主要内容,如果未能解决你的问题,请参考以下文章

在kotlin的自定义类型arraylist中按id搜索对象[重复]

Java基础语法(自定义类ArrayList集合)

java基础:自定义类ArrayList集合

Arraylist中contains方法底层实现解读与HashSet自定义类型去重效果的简述(接上一篇)

Kotlin - ArrayList 的自定义排序

自定义对象的 Android ArrayList - 保存到 SharedPreferences - 可序列化?