我有一张表格,它映射了String-> Integer。
我想用数据库中的值填充枚举,而不是静态创建枚举。这可能吗?
所以,而不是静态地删除这个:
public enum Size { SMALL(0), MEDIUM(1), LARGE(2), SUPERSIZE(3) };
我想动态创建这个枚举,因为数字{0,1,2,3}基本上是随机的(因为它们是由数据库的AUTOINCREMENT列自动生成的)。
答案 0 :(得分:30)
没有。枚举总是在编译时固定。你能做到这一点的唯一方法是动态生成相关的字节码。
话虽如此,你应该弄清楚你真正感兴趣的枚举的哪些方面。大概你不想对它们使用switch
语句,因为这意味着静态代码和你不静态地知道值...同样代码中的任何其他引用。
如果你真的只想要一张从String
到Integer
的地图,你可以使用你在执行时填充的Map<String, Integer>
,然后你就完成了。如果你想要EnumSet
功能,那么以相同的效率再现它们会有点棘手,但是通过一些努力它可能是可行的。
所以,在进一步考虑实施之前,我建议你弄清楚你的实际需求是什么。
(编辑:我一直认为这个枚举是完全动态的,即你不知道名字,甚至不知道有多少个值。如果这组名称是固定的,你只能 需要从数据库中获取ID,这是一个非常不同的问题 - 请参阅Andreas' answer。)
答案 1 :(得分:23)
这有点棘手,因为这些值的数量发生在类加载时。因此,您需要静态访问数据库连接。
尽管我重视他的答案,但我认为Jon Skeet这次可能错了。
看看这个:
public enum DbEnum {
FIRST(getFromDb("FIRST")), SECOND(getFromDb("second"));
private static int getFromDb(String s) {
PreparedStatement statement = null;
ResultSet rs = null;
try {
Connection c = ConnectionFactory.getInstance().getConnection();
statement = c.prepareStatement("select id from Test where name=?");
statement.setString(1, s);
rs = statement.executeQuery();
return rs.getInt(1);
}
catch (SQLException e) {
throw new RuntimeException("error loading enum value for "+s,e);
}
finally {
try {
rs.close();
statement.close();
} catch (SQLException e) {
//ignore
}
}
throw new IllegalStateException("have no database");
}
final int value;
DbEnum(int value) {
this.value = value;
}
}
答案 2 :(得分:6)
改进what Andreas did,您可以将数据库的内容加载到地图中,以减少所需的数据库连接数。
public enum DbEnum {
FIRST(getFromDb("FIRST")),
SECOND(getFromDb("second"));
private Map<String,Integer> map;
private static int getFromDB(String s)
{
if (map == null)
{
map = new HashMap<String,Integer>();
// Continue with database code but get everything and
// then populate the map with key-value pairs.
return map.get(s);
}
else {
return map.get(s); }
}
}
答案 3 :(得分:3)
枚举不是动态的,所以简短的回答是你不能这样做。
另请参阅Stack Overflow问题 Dynamic enum in C# 。
答案 4 :(得分:1)
您需要在代码中复制数据库中的内容(反之亦然)。有关一些好的建议,请参阅此question。
答案 5 :(得分:0)
在所有语言中,我知道枚举是静态的。编译器可以对它们进行一些优化。因此简短的答案是否定的,你不能。
问题是为什么要以这种方式使用枚举。你能指望什么? 或者换句话说为什么不使用集合呢?