Domanda

Qual è il modo corretto per eseguire il cast di un Int a un'enum in Java data la seguente enum?

public enum MyEnum
{
    EnumValue1,
    EnumValue2
}


MyEnum enumValue = (MyEnum) x; //Doesn't work???
È stato utile?

Soluzione

Prova MyEnum.values()[x] dove x deve essere 0 o 1, ovvero un numero ordinale valido per quell'enumerazione.

Nota che in Java le enumerazioni sono in realtà classi (e quindi i valori enum sono oggetti) e quindi non puoi eseguire il cast di un int o anche Integer su un enum.

Altri suggerimenti

MyEnum.values()[x] è un'operazione costosa.Se le prestazioni sono un problema, potresti voler fare qualcosa del genere:

public enum MyEnum {
    EnumValue1,
    EnumValue2;

    public static MyEnum fromInteger(int x) {
        switch(x) {
        case 0:
            return EnumValue1;
        case 1:
            return EnumValue2;
        }
        return null;
    }
}

Se vuoi fornire i tuoi valori interi, puoi usare una struttura come sotto

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;
        }
}

Puoi provare in questo modo.
Crea classe con ID elemento.

      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;
            }
      }

Ora recupera questo Enum utilizzando id come int.

MyEnum myEnum = MyEnum.fromId(5);

Memorizzo i valori nella cache e creo un semplice metodo di accesso statico:

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];
    }
}

Le enumerazioni Java non hanno lo stesso tipo di mappatura da enum a int che hanno in C ++.

Detto questo, tutte le enumerazioni hanno un metodo values che restituisce un array di possibili valori enum, quindi

MyEnum enumValue = MyEnum.values()[x];

dovrebbe funzionare.È un po 'brutto e potrebbe essere meglio non provare a convertire da ints a Enums (o viceversa) se possibile.

Questo non è qualcosa che viene fatto di solito, quindi riconsidererei.Ma detto questo, le operazioni fondamentali sono: int -> enum utilizzando EnumType.values () [intNum] e enum -> int utilizzando enumInst.ordinal ().

Tuttavia, poiché qualsiasi implementazione di values () non ha altra scelta che darti una copia dell'array (gli array java non sono mai di sola lettura), sarebbe meglio usare una EnumMap per memorizzare nella cache enum -> intmappatura.

Utilizza MyEnum enumValue = MyEnum.values()[x];

Ecco la soluzione che intendo adottare.Non solo funziona con numeri interi non sequenziali, ma dovrebbe funzionare con qualsiasi altro tipo di dati che potresti voler utilizzare come ID sottostante per i tuoi valori enum.

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;
    }
}

Ho solo bisogno di convertire gli ID in enumerazioni in momenti specifici (durante il caricamento dei dati da un file), quindi non c'è motivo per me di mantenere la mappa in memoria in ogni momento.Se hai bisogno che la mappa sia sempre accessibile, puoi sempre memorizzarla nella cache come membro statico della tua classe Enum.

Nel caso in cui aiuti gli altri, l'opzione che preferisco, che non è elencata qui, utilizza Funzionalità di Guava's Maps :

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);
    }
}

Con l'impostazione predefinita puoi utilizzare null, puoi throw IllegalArgumentException oppure il tuo fromInt potrebbe restituire un Optional, qualunque sia il comportamento che preferisci.

Puoi iterare su values() di enum e confrontare il valore intero di enum con un dato id come di seguito:

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
    }
}

E usa proprio in questo modo:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
Spero che questo aiuti;)

Sulla base della risposta di @ChadBefus e del commento di @shmosel, ti consiglio di utilizzarlo.(Ricerca efficiente e funziona su java puro>= 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());
    }
}

In Kotlin:

enum class Status(val id: Int) {
    NEW(0), VISIT(1), IN_WORK(2), FINISHED(3), CANCELLED(4), DUMMY(5);

    companion object {
        private val statuses = Status.values().associateBy(Status::id)

        fun getStatus(id: Int): Status? = statuses[id]
    }
}

Utilizzo:

val status = Status.getStatus(1)!!

Una buona opzione è quella di evitare la conversione da int a enum: ad esempio, se hai bisogno del valore massimo, puoi confrontare x.ordinal () con y.ordinal () e restituire x oy corrispondentemente.(Potrebbe essere necessario riordinare i valori per rendere significativo tale confronto.)

Se ciò non è possibile, memorizzerei MyEnum.values() in un array statico.

Questa è la stessa risposta dei medici ma mostra come eliminare il problema con gli array mutabili.Se si utilizza questo tipo di approccio a causa della predizione del ramo prima, avrà un effetto minimo o nullo e l'intero codice chiama solo la funzione mutable array values () solo una volta.Poiché entrambe le variabili sono statiche, non consumeranno n * memoria per ogni utilizzo di questa enumerazione.

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;
        }
    }
}

Questo dovrebbe risolvere gli indici che non sono più sincronizzati con il problema del valore ordinale.

package service.manager;

public enum Command {
    PRINT_FOO(0),
    PRINT_BAR(2),
    PRINT_BAZ(3);

    public int intVal;
    Command(int intVal){
        this.intVal = intVal;
    }

    /**
     * Functionality to ascertain an enum from an int
     * The static block initializes the array indexes to correspond with it's according ordinal value
     * Simply use Command.values[index] or get the int value by e.g. Command.PRINT_FOO.intVal;
     * */
    public static Command values[];
    static{
        int maxVal = -1;
        for(Command cmd : Command.values())
            if(maxVal < cmd.intVal)
                maxVal = cmd.intVal;

        values = new Command[maxVal + 1];

        for(Command cmd : Command.values())
            values[cmd.intVal] = cmd;
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top