28

String->Integer をマップするテーブルがあります。

列挙型を静的に作成するのではなく、列挙型にデータベースの値を入力したいと考えています。これは可能ですか?

したがって、これを静的に宣言するのではなく、次のようにします。

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

数値 {0,1,2,3} は基本的にランダムであるため (データベースの AUTOINCREMENT 列によって自動生成されるため)、この列挙型を動的に作成したいと考えています。

4

6 に答える 6

35

いいえ。列挙型は常にコンパイル時に修正されます。これを行う唯一の方法は、関連するバイトコードを動的に生成することです。

そうは言っても、おそらく列挙型のどの側面に実際に興味があるかを判断する必要があります。おそらく、switch静的コードを意味し、静的に値がわからないため、それらに対してステートメントを使用したくないでしょう。 .. 同様に、コード内の他の参照。

String本当に からへのマップが必要な場合は、実行時に入力する をInteger使用するだけで完了です。Map<String, Integer>機能が必要な場合EnumSet、同じ効率で再現するのはやや難しいですが、多少の努力で実現可能になる場合があります。

したがって、実装について考えるという観点から先に進む前に、実際の要件が何であるかを理解することをお勧めします。

(編集:私は、この列挙型が完全に動的であると想定してきました。つまり、名前や、存在する値の数すら知らないと仮定しています。名前のセットが固定されていて、データベースから ID を取得するだけでよい場合、それは非常に別の問題です-アンドレアスの答えを参照してください。)

于 2009-05-12T06:50:12.373 に答える
27

これらの値の入力はクラスのロード時に発生するため、これは少し注意が必要です。したがって、データベース接続への静的アクセスが必要になります。

私は彼の答えを大切にしていますが、今回はジョン・スキートが間違っているのではないかと思います。

これを見てください:

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 question Dynamic enum in C# もご覧ください。

于 2009-05-12T06:50:44.540 に答える
1

データベースにあるものをコードで複製する必要があります(またはその逆)。いくつかの良いアドバイスについては、この質問を参照してください。

于 2009-05-12T07:09:16.053 に答える
0

私が知っているすべての言語で、列挙型は静的です。コンパイラーはそれらに対していくつかの最適化を行うことができます。したがって、簡単な答えはノーです、あなたはできません。

問題は、なぜこのように列挙型を使用したいのかということです。何を期待しますか?つまり、代わりにコレクションを使用してみませんか?

于 2009-05-12T06:57:14.157 に答える