【问题标题】:How to make an object that is of the class that is specified in a string?如何创建一个属于字符串中指定的类的对象?
【发布时间】:2015-06-14 05:02:42
【问题描述】:

我有一款游戏运行在与 terraria 或 minecraft 类似的系统上,至少在块状方面是这样。

我以每个块都是一个对象的方式构造它,并且每种类型的块都有一个特定的类(扩展 BlockObject 原型)。

我让游戏将块保存在如下文件中

我得到我正在保存的对象实例的名称,并将其存储在一个字符串中 我开始将给定对象的信息写入具有类名称的字符串中(表示它是什么类型的块,例如,作为 BlockGrass.java 对象的块将存储为 BlockGrass)。 通常,当从保存文件读取信息时,我正在读取保存文件,当它获取块的信息时,它首先将块类型保存在本地字符串中(在这种情况下为 BlockGrass),还保存位置(x 坐标和y 坐标)。然后它将运行一系列 if 语句,如下所示

if(blockType.equals("BlockGrass"))
{
blocksArray.add(new BlockGrass(...));
}
else if(blockType.equals("BlockStone"))
{
blocksArray.add(new BlockStone(...));
}
etc

现在我想让我的游戏动态变化,并且如果有人决定制作一个新的 Block 类(修改游戏),他们不必修改 MapReader 类。因此,与其运行如上所示的一系列 if 语句(每次创建一个新的块类,都必须为该块放置一个新的 if 语句),我想要它,以便它创建一个具有的类的新对象与 BlockType 同名。为了让您更好地了解以下内容

BlocksArray.add(new blockType(...));

上面显示的内容不起作用的原因是因为 blockType 是一个字符串,其中包含我要使用的类的名称。不是类名

如果不使用 if 语句,我怎么能做这样的事情?

【问题讨论】:

  • 使用 Class.forName(String).newInstance();
  • 您似乎在重新发明序列化?
  • @redge 虽然这确实给了我类的实例,但我不能这样做.add(new Class.forName(String).newInstance());
  • 创建一个通用工厂,它接收一个应该扩展超类的块类型,然后您只需传递块类型引用并返回块类型的正确实例...

标签: java string class object


【解决方案1】:

您要做的是利用 BlockObject 层次结构中的多态行为。因此使用class.forName 是一个好方法。在 Class 变量上调用 newInstance() 后,您需要将其强制转换为 BlockObject 类层次结构的基类(您称之为原型)。 W可以保证,由于真正的类是继承BlockObject的,所以根据继承的定义,它是一个BlockObject。

这是一个例子

public class GameLoader {

    private List<BlockObject> blocksArray = new ArrayList<BlockObject>();

    public Object getNewBlock(String blockClassName) throws     ClassNotFoundException, InstantiationException, IllegalAccessException {

        Class blockClass = Class.forName(blockClassName);
        return blockClass.newInstance();

    }

    public void addNewBlockType(String typeName) throws     ClassNotFoundException, InstantiationException, IllegalAccessException {

        BlockObject castedType = (BlockObject)getNewBlock(typeName); 
        blocksArray.add(castedType);
    }
}

在此类对象上调用的任何基类方法都将显示多态行为。

【讨论】:

  • 现在我有一个问题,构造函数呢,我假设在这种情况下它没有被调用?
  • @yoseph1998,是的,它被称为Class.newInstance() Creates a new instance of the class represented by this Class object. The class is instantiated as if by a new expression with an empty argument list.(参见:docs.oracle.com/javase/7/docs/api/java/lang/…)。因此如果自定义构造函数,一定要提供与默认构造函数类似的构造函数
  • 如果你需要调用一个有参数的构造,你需要深入反射 API 并调用 blockClass.getConstructor (....).newInstance(...) docs.oracle.com/javase/7/docs/api/java/lang/…
  • 现在我有一个问题?将它连接到父类会删除一些功能,例如如果块中有更多具有未知类型的方法,而不是 BlockObject 类。如果未知块上的构造函数与 BlockObject 不同怎么办。
【解决方案2】:

这不是编译和检查的,它只是表明必须做什么。

// first get the class
Class<?> rawclass = Class.forName(String);
// then check an object will fit where you want it.
if (BlockObject.class.isAssignableFrom(rawclass)){
      // create the object, cast it to the correct type and add it
      BlockObject object = (BlockObject) rawclass.newInstance();
      blockArray.add(object);
}

在 forName 和 newInstance 方法中会有一些例外。

【讨论】:

    猜你喜欢
    • 2018-05-19
    • 2013-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多