我有一个将字符串映射为整数的表。
我想从数据库中获取值来填充这个枚举类型,而不是静态地创建一个枚举。这种做法可行吗?
所以,我不希望像这样静态声明枚举:
public enum Size { SMALL(0), MEDIUM(1), LARGE(2), SUPERSIZE(3) };
我希望动态创建此枚举,因为数字 {0,1,2,3} 实际上是随机的(因为它们是由数据库的自增列自动生成的)。
我有一个将字符串映射为整数的表。
我想从数据库中获取值来填充这个枚举类型,而不是静态地创建一个枚举。这种做法可行吗?
所以,我不希望像这样静态声明枚举:
public enum Size { SMALL(0), MEDIUM(1), LARGE(2), SUPERSIZE(3) };
我希望动态创建此枚举,因为数字 {0,1,2,3} 实际上是随机的(因为它们是由数据库的自增列自动生成的)。
不行。枚举在编译时总是固定的。你能做的唯一方式就是动态生成相关字节码。
尽管如此,你应该明确自己真正感兴趣的枚举方面。假设你不想在它们上使用 switch
语句,因为那意味着静态代码且你不知道静态值...同样,代码中的其他任何引用也是如此。
如果你只需要一个从 String
到 Integer
的映射表,你可以在执行时使用 Map<String, Integer>
并填充内容,然后完成任务。如果你需要 EnumSet
功能,要以相同效率进行复制将会有点棘手,但是通过一些努力可能是可行的。
因此,在思考实现的任何进一步步骤之前,建议您先确定自己的真正需求。
(编辑:我一直假定这个枚举是完全动态的,即你不知道名称甚至不知道有多少值。如果名称集合是固定的,而你仅仅需要从数据库获取 ID,那就完全不同了 - 参见Andreas' answer。)
这有点棘手,因为那些值的种群发生在类加载时期。所以你需要对数据库连接进行静态访问。
虽然我非常重视他的回答,但我认为这次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;
}
}
在Andreas所做的基础上,您可以将数据库内容加载到映射中,以减少所需的数据库连接数量。
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); }
}
}
==
比较即可。如果另外确保单例在应用程序加载期间自动初始化,那么我们可以避免使用枚举。 - YoYo