28

我有一个映射字符串-> 整数的表。

我不想静态创建枚举,而是想用数据库中的值填充枚举。这可能吗 ?

因此,而不是静态地对此进行处理:

public enum Size { SMALL(0), MEDIUM(1), LARGE(2), SUPERSIZE(3) };

我想动态创建这个枚举,因为数字 {0,1,2,3} 基本上是随机的(因为它们是由数据库的 AUTOINCREMENT 列自动生成的)。

4

6 回答 6

35

不,枚举总是在编译时固定的。您可以做到这一点的唯一方法是动态生成相关的字节码。

话虽如此,您可能应该弄清楚您真正感兴趣的枚举的哪些方面。大概您不想对switch它们使用语句,因为这意味着静态代码并且您不知道静态值。 .. 代码中的任何其他引用也是如此。

如果您真的只想要一个从Stringto的地图Integer,您可以使用Map<String, Integer>在执行时填充的 a ,然后就完成了。如果您想要这些EnumSet功能,以相同的效率重现它们会有些棘手,但通过一些努力可能是可行的。

因此,在进一步考虑实施之前,我建议您弄清楚您的真正需求是什么。

(编辑:我一直假设这个枚举是完全动态的,即您不知道名称,甚至不知道有多少值。如果名称集是固定的,您只需要从数据库中获取 ID ,这是一个非常不同的问题 - 见安德烈亚斯的回答。)

于 2009-05-12T06:50:12.373 回答
27

这有点棘手,因为这些值的填充发生在类加载时。因此,您将需要对数据库连接的静态访问。

尽管我很重视他的回答,但我认为 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;
    }
}
于 2009-05-12T07:01:00.920 回答
6

改进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); }
    }
}
于 2012-11-20T12:27:59.267 回答
3

枚举不是动态的,所以简短的回答是你不能这样做。

另请查看 Stack Overflow 问题Dynamic enum in C#

于 2009-05-12T06:50:44.540 回答
1

您需要在代码中复制数据库中的内容(反之亦然)。有关一些好的建议,请参阅此问题

于 2009-05-12T07:09:16.053 回答
0

在我知道的所有语言中,枚举都是静态的。编译器可以对它们进行一些优化。因此,简短的回答是否定的,你不能。

问题是为什么要以这种方式使用枚举。你能指望什么?或者换句话说,为什么不使用集合呢?

于 2009-05-12T06:57:14.157 回答