我正在编写一个程序来模拟一个名为“文明4”的游戏中的城市。为了做到这一点,我有几个枚举来表示该城市拥有的每个地块的地形,资源,改进等类型。
问题是我想编程与Fan制作的mod兼容,这可能会为游戏添加需要被我的独立实用程序接受的东西。所以我想创建一个Enum style 类来保存由加载的mods定义的新类型(因为在运行时无法更改枚举),这是在用户输入要加载的mod时在运行时创建的(这是一个解析为读取新添加的txt文件)
那么有没有办法模拟在运行时创建并添加到 的枚举?我认为静态成员变量不能用,因为它们是在运行时之前完成的......
答案 0 :(得分:2)
您可以enum
实现接口。
这样您可以在枚举中定义您的定义值,但新值可以是实现接口的任何类。
另一种方法是使用字节代码生成器或编译器API在运行时生成或加载enum
。我写了一个库,以便更容易获取String并编译和加载它。
答案 1 :(得分:1)
嗯,Java中的枚举只是一种类,其中语言保证已知对象的集合在编译时是已知的并且是有限的。如果要在运行时添加新的枚举文字,最终会得到常规类。
答案 2 :(得分:1)
枚举的美妙之处在于,您可以在代码中编写人类可读的名称,这些代码在幕后编译为数字,因为数字之类的计算机更好。以这个枚举为例:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
在幕后WINTER可能是0(零),SPRING是1等。 要在运行时代码中复制此行为,您可以创建一个字符串列表,如下所示:
List<String> seasons;
seasons = new ArrayList<String>();
seasons.add("Winter");
seasons.add("Spring");
...
通过这种方式,您可以将项目引用为数字,例如season [1]将等于“Spring”。 这个答案只是解决这个问题的众多方法之一。
答案 3 :(得分:1)
默认情况下,enum
类型只有一定数量的值。 enum
类型中的值实际上声明为static final
,并且无法在运行时添加更多内容。
话虽如此,您可以使用其他模式来实现您想要的效果。我们来看看使用接口和注册系统。我们将从Terrain
界面开始:
public interface Terrain {
int getId();
String getName();
int getSightBonus();
}
现在是enum
,DefaultTerrain
:
public enum DefaultTerrain implements Terrain {
PLAINS(0, "Plains", 1),
HILLS(1, "Hills", -1),
MOUNTAINS(2, "Mountains", -2);
private int id;
private String name;
private int sightBonus;
private DefaultTerrain(int id, String name, int sightBonus) {
this.id = id;
this.name = name;
this.sightBonus = sightBonus;
}
public int getId() {return id;}
public String getName() {return name;}
public int getSightBonus() {return sightBonus;}
}
注册类,可以是静态实用程序类,也可以是单例。
public class TerrainManager {
private static Map<Integer, Terrain> terrainsById = new HashMap<>();
static {
for (DefaultTerrain terrain : DefaultTerrain.values())
register(terrain);
}
public static void register(Terrain terrain) {
Integer id = terrain.getId();
if (terrainsById.contains(terrain.getId()))
throw new IllegalArgumentException("Terrain with id already exists: " + id);
terrainsById.put(id, terrain);
}
public static Terrain getTerrainById(int id) {
return terrainsById.get(id);
}
public static Set<Terrain> getAllTerrains() {
return new HashSet<Terrain>(terrainsById.values());
}
}
这最后一堂课是魔术发生的地方。据推测,模仿者会在游戏的世界定义中使用某种标识符来说“使用这个图块”,对吧?在这种情况下,我将其称为整数id
,但实际上它可以是任何类型,只需相应地修改Map
即可。在地图加载代码中,只需使用世界定义中的ID即可查找Terrain
。当modder添加新的Terrain
时,他们只需要实现Terrain
并将其注册到TerrainManager
。
static
初始值设定项可确保在添加任何其他内容之前添加DefaultTerrain
个对象。如果使用单例,则可以将其放入类构造函数中。
将此模式用于您希望用户添加到的不同enum
类型。除了enum
之外,您还可以将它用于几乎任何其他类型。
答案 4 :(得分:0)
您需要CGLIB,http://cglib.sourceforge.net/