¿Cuál es la forma correcta de convertir un Int en una enumeración en Java dada la siguiente enumeración?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
¿Cuál es la forma correcta de convertir un Int en una enumeración en Java dada la siguiente enumeración?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Respuestas:
Pruebe MyEnum.values()[x]
dónde x
debe estar 0
o 1
, es decir, un ordinal válido para esa enumeración.
Tenga en cuenta que en Java las enumeraciones en realidad son clases (y los valores de enumeración son, por lo tanto, objetos) y, por lo tanto, no puede convertir una enumeración int
o incluso Integer
a una enumeración.
MyEnum.values()
ya que es costoso. es decir, si lo llamas cientos de veces.
MyEnum.values()[x]
Es una operación costosa. Si el rendimiento es una preocupación, es posible que desee hacer algo como esto:
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]
una operación costosa? No sé cómo funciona en detalles, pero para mí parece que acceder a un elemento en una matriz no sería gran cosa, también conocido como tiempo constante. Si la matriz tiene que compilarse, toma O (n) tiempo, que es el mismo tiempo de ejecución que su solución.
values()
genera una nueva matriz cada vez, porque las matrices son mutables, por lo que no sería seguro devolver la misma varias veces. Las instrucciones de cambio no son necesariamente O (n), se pueden compilar para saltar tablas. Entonces las afirmaciones de Lorenzo parecen justificadas.
myEnum = myEnumValues[i]
aún devolverá el i
elemento th en la enumeración sin cambios.
Si desea dar sus valores enteros, puede usar una estructura como la siguiente
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;
}
}
Puedes intentarlo así.
Crear clase con elemento 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;
}
}
Ahora obtenga esta enumeración usando id como int.
MyEnum myEnum = MyEnum.fromId(5);
Guardo en caché los valores y creo un método de acceso estático simple:
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
el mismo nombre que el método values()
. Yo uso cachedValues
para el nombre del campo.
Las enumeraciones de Java no tienen el mismo tipo de asignación de enumeración a int que tienen en C ++.
Dicho esto, todas las enumeraciones tienen un values
método que devuelve una matriz de posibles valores de enumeración, por lo que
MyEnum enumValue = MyEnum.values()[x];
Deberia trabajar. Es un poco desagradable y podría ser mejor no intentar convertir de int
s a Enum
s (o viceversa) si es posible.
Esto no es algo que generalmente se hace, así que lo reconsideraría. Pero dicho esto, las operaciones fundamentales son: int -> enum usando EnumType.values () [intNum], y enum -> int usando enumInst.ordinal ().
Sin embargo, dado que cualquier implementación de valores () no tiene más remedio que darle una copia de la matriz (las matrices java nunca son de solo lectura), será mejor que use un EnumMap para almacenar en caché la asignación enum -> int.
Aquí está la solución con la que planeo ir. Esto no solo funciona con enteros no secuenciales, sino que también debería funcionar con cualquier otro tipo de datos que desee utilizar como ID subyacente para sus valores de enumeración.
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;
}
}
Solo necesito convertir las identificaciones en enumeraciones en momentos específicos (cuando se cargan datos de un archivo), por lo que no hay ninguna razón para mantener el Mapa en la memoria en todo momento. Si necesita que el mapa esté accesible en todo momento, siempre puede almacenarlo en caché como miembro estático de su clase Enum.
clearCachedValues
cuando termine de usarlo (eso establece el campo privado de nuevo a nulo). Considero MyEnum.fromInt(i)
más fácil de entender que pasar un objeto de mapa.
En caso de que ayude a otros, la opción que prefiero, que no se encuentra aquí, utiliza la funcionalidad de Mapas de Guava :
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 el valor predeterminado que puede usar null
, puede throw IllegalArgumentException
o fromInt
puede devolver un Optional
comportamiento que prefiera.
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
método también.
Puede iterar sobre values()
enum y comparar el valor entero de enum con los dados id
a continuación:
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
}
}
Y use así:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
espero que esto ayude;)
Según la respuesta de @ChadBefus y el comentario de @shmosel, recomendaría usar esto. (Búsqueda eficiente, y funciona en 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());
}
}
Una buena opción es evitar la conversión de int
a enum
: por ejemplo, si necesita el valor máximo, puede comparar x.ordinal () con y.ordinal () y devolver x o y en consecuencia. (Es posible que deba reordenar sus valores para que dicha comparación sea significativa).
Si eso no es posible, lo almacenaría MyEnum.values()
en una matriz estática.
Esta es la misma respuesta que los médicos, pero muestra cómo eliminar el problema con las matrices mutables. Si usa este tipo de enfoque debido a la predicción de ramificación, primero tendrá un efecto de muy poco a cero y el código completo solo llama a los valores de matriz mutable () funcionan solo una vez. Como ambas variables son estáticas, tampoco consumirán n * memoria para cada uso de esta enumeració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;
}
}
}
En 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]
}
}
Uso:
val status = Status.getStatus(1)!!
Escribió esta implementación. Permite valores perdidos, valores negativos y mantiene el código consistente. El mapa también se almacena en caché. Utiliza una interfaz y necesita Java 8.
Enum
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);
}
}
Interfaz
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;
}
}