次の列挙型を与えられたJavaの列挙型にIntをキャストする正しい方法は何ですか?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
次の列挙型を与えられたJavaの列挙型にIntをキャストする正しい方法は何ですか?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
回答:
MyEnum.values()[x]
where x
が0
or でなければならない1
、つまり、その列挙型の有効な序数を試してください。
Javaで実際のクラス(と列挙値はこのようにオブジェクトである)されている列挙型ことに注意してくださいので、あなたはキャストすることはできませんint
かさえInteger
列挙型に。
MyEnum.values()
が高価になる可能性があります。つまり、何百回と呼ばれる場合です。
MyEnum.values()[x]
高価な操作です。パフォーマンスが気になる場合は、次のようにすることをお勧めします。
public enum MyEnum {
EnumValue1,
EnumValue2;
public static MyEnum fromInteger(int x) {
switch(x) {
case 0:
return EnumValue1;
case 1:
return EnumValue2;
}
return null;
}
}
MyEnum.values()[x]
高価な操作と見なすのか説明できますか?詳細はわかりませんが、配列内の要素にアクセスすることは、大したことではなく、一定の時間であるように思えます。アレイを構築する必要がある場合、O(n)時間かかります。これは、ソリューションと同じ実行時間です。
values()
配列は可変なので、同じ配列を複数回返すのは安全ではないため、毎回新しい配列を生成すると思います。switchステートメントは必ずしもO(n)である必要はありません。それらはジャンプテーブルにコンパイルできます。したがって、ロレンツォの主張は正当化されているようです。
myEnum = myEnumValues[i]
でも、i
変更なしで列挙型のth番目の項目が返されます。
整数値を指定する場合は、以下のような構造を使用できます
public enum A
{
B(0),
C(10),
None(11);
int id;
private A(int i){id = i;}
public int GetID(){return id;}
public boolean IsEmpty(){return this.equals(A.None);}
public boolean Compare(int i){return id == i;}
public static A GetValue(int _id)
{
A[] As = A.values();
for(int i = 0; i < As.length; i++)
{
if(As[i].Compare(_id))
return As[i];
}
return A.None;
}
}
このようにしてみてください。
要素IDを持つクラスを作成します。
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public static MyEnum fromId(int id) {
for (MyEnum type : values()) {
if (type.getId() == id) {
return type;
}
}
return null;
}
}
次に、idをintとして使用して、このEnumをフェッチします。
MyEnum myEnum = MyEnum.fromId(5);
値をキャッシュして、単純な静的アクセスメソッドを作成します。
public static enum EnumAttributeType {
ENUM_1,
ENUM_2;
private static EnumAttributeType[] values = null;
public static EnumAttributeType fromInt(int i) {
if(EnumAttributeType.values == null) {
EnumAttributeType.values = EnumAttributeType.values();
}
return EnumAttributeType.values[i];
}
}
values
にメソッドと同じ名前を付けない方が混乱が少なくなりますvalues()
。cachedValues
フィールド名に使用しています。
これは通常行われることではないので、再考します。ただし、基本的な操作は次のとおりです。int-> EnumType.values()[intNum]を使用した列挙型、およびenumInst.ordinal()を使用した列挙型-> int。
ただし、values()の実装には配列のコピーを提供するしかありません(Java配列は読み取り専用ではありません)ため、EnumMapを使用してenum-> intマッピングをキャッシュするほうが適切です。
これが私が計画している解決策です。これは非順次整数で機能するだけでなく、列挙値の基礎となるIDとして使用する可能性のある他のデータ型でも機能するはずです。
public Enum MyEnum {
THIS(5),
THAT(16),
THE_OTHER(35);
private int id; // Could be other data type besides int
private MyEnum(int id) {
this.id = id;
}
public int getId() {
return this.id;
}
public static Map<Integer, MyEnum> buildMap() {
Map<Integer, MyEnum> map = new HashMap<Integer, MyEnum>();
MyEnum[] values = MyEnum.values();
for (MyEnum value : values) {
map.put(value.getId(), value);
}
return map;
}
}
特定の時間(ファイルからデータをロードするとき)にIDを列挙型に変換するだけでよいので、マップを常にメモリに保持する理由はありません。いつでもマップにアクセスできるようにする必要がある場合は、いつでもEnumクラスの静的メンバーとしてマップをキャッシュできます。
clearCachedValues
を使用し、使用が終わったら2番目のメソッドを追加します(プライベートフィールドをnullに戻します)。MyEnum.fromInt(i)
マップオブジェクトを渡すよりも理解しやすいと思います。
他の人を助けるために、ここにリストされていない私が好むオプションは、グアバのマップ機能を使用しています:
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static ImmutableMap<Integer, MyEnum> reverseLookup =
Maps.uniqueIndex(Arrays.asList(MyEnum.values())), MyEnum::getValue);
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
}
デフォルトではを使用null
できthrow IllegalArgumentException
ますfromInt
がOptional
、好きな動作をすることができます。
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
メソッドも定義したいかもしれません。
values()
enumを反復処理して、enumの整数値をid
以下のように指定された値と比較できます。
public enum TestEnum {
None(0),
Value1(1),
Value2(2),
Value3(3),
Value4(4),
Value5(5);
private final int value;
private TestEnum(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static TestEnum getEnum(int value){
for (TestEnum e:TestEnum.values()) {
if(e.getValue() == value)
return e;
}
return TestEnum.None;//For values out of enum scope
}
}
そして、このように使用してください:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
これが役に立てば幸いです;)
@ChadBefusの回答と@shmoselコメントに基づいて、これを使用することをお勧めします。(効率的なルックアップ、および純粋なJava> = 8で動作)
import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Map;
import java.util.Arrays;
public enum MyEnum {
OPTION_1(-66),
OPTION_2(32);
private int value;
private MyEnum(final int value) {
this.value = value;
}
public int getValue() {
return this.value;
}
private static Map<Integer, MyEnum> reverseLookup =
Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
public static MyEnum fromInt(final int id) {
return reverseLookup.getOrDefault(id, OPTION_1);
}
public static void main(String[] args) {
System.out.println(fromInt(-66).toString());
}
}
良いオプションがあるに避けてから変換int
するenum
:あなたは最大値が必要な場合たとえば、あなたは(y.ordinal)、それに応じてリターンxまたはyに)(x.ordinal比較することができます。(このような比較を意味のあるものにするために、値を並べ替える必要があるかもしれません。)
それが不可能な場合はMyEnum.values()
、静的配列に格納します。
これは医師と同じ答えですが、可変配列の問題を解消する方法を示しています。最初に分岐予測のためにこの種のアプローチを使用する場合、ifの効果はほとんどなく、コード全体は可変配列のvalues()関数を1回だけ呼び出します。どちらの変数も静的であるため、この列挙の使用ごとにn *メモリを消費しません。
private static boolean arrayCreated = false;
private static RFMsgType[] ArrayOfValues;
public static RFMsgType GetMsgTypeFromValue(int MessageID) {
if (arrayCreated == false) {
ArrayOfValues = RFMsgType.values();
}
for (int i = 0; i < ArrayOfValues.length; i++) {
if (ArrayOfValues[i].MessageIDValue == MessageID) {
return ArrayOfValues[i];
}
}
return RFMsgType.UNKNOWN;
}
enum MyEnum {
A(0),
B(1);
private final int value;
private MyEnum(int val) {this.value = value;}
private static final MyEnum[] values = MyEnum.values();//cache for optimization
public static final getMyEnum(int value) {
try {
return values[value];//OOB might get triggered
} catch (ArrayOutOfBoundsException e) {
} finally {
return myDefaultEnumValue;
}
}
}
この実装を書きました。欠損値、負の値を許容し、コードの一貫性を保ちます。マップもキャッシュされます。インターフェイスを使用し、Java 8が必要です。
列挙型
public enum Command implements OrdinalEnum{
PRINT_FOO(-7),
PRINT_BAR(6),
PRINT_BAZ(4);
private int val;
private Command(int val){
this.val = val;
}
public int getVal(){
return val;
}
private static Map<Integer, Command> map = OrdinalEnum.getValues(Command.class);
public static Command from(int i){
return map.get(i);
}
}
インターフェース
public interface OrdinalEnum{
public int getVal();
@SuppressWarnings("unchecked")
static <E extends Enum<E>> Map<Integer, E> getValues(Class<E> clzz){
Map<Integer, E> m = new HashMap<>();
for(Enum<E> e : EnumSet.allOf(clzz))
m.put(((OrdinalEnum)e).getVal(), (E)e);
return m;
}
}