Was ist der richtige Weg, um ein Int in eine Aufzählung in Java umzuwandeln, wenn die folgende Aufzählung vorliegt?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Was ist der richtige Weg, um ein Int in eine Aufzählung in Java umzuwandeln, wenn die folgende Aufzählung vorliegt?
public enum MyEnum
{
EnumValue1,
EnumValue2
}
MyEnum enumValue = (MyEnum) x; //Doesn't work???
Antworten:
Versuchen Sie, MyEnum.values()[x]
wo sein x
muss 0
oder 1
dh eine gültige Ordnungszahl für diese Aufzählung.
Beachten Sie, dass Aufzählungen in Java tatsächlich Klassen sind (und Aufzählungswerte somit Objekte sind) und Sie daher keine int
oder sogar Integer
keine Aufzählung umwandeln können.
MyEnum.values()
da dies teuer ist. dh wenn Sie es hunderte Male nennen.
MyEnum.values()[x]
ist eine teure Operation. Wenn die Leistung ein Problem darstellt, möchten Sie möglicherweise Folgendes tun:
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]
eine teure Operation betrachten. Ich weiß nicht, wie es im Detail funktioniert, aber für mich scheint es keine große Sache zu sein, auf ein Element in einem Array zuzugreifen, auch bekannt als konstante Zeit. Wenn das Array erstellt werden muss, dauert es O (n), was der Laufzeit Ihrer Lösung entspricht.
values()
aus, dass jedes Mal ein neues Array generiert wird, da Arrays veränderbar sind und es nicht sicher ist, dasselbe mehrmals zurückzugeben. Switch-Anweisungen sind nicht unbedingt O (n), sie können zu Sprungtabellen kompiliert werden. Lorenzos Behauptungen scheinen also berechtigt zu sein.
myEnum = myEnumValues[i]
wird das i
dritte Element in der Aufzählung ohne Änderungen zurückgegeben.
Wenn Sie Ihre ganzzahligen Werte angeben möchten, können Sie eine Struktur wie die folgende verwenden
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;
}
}
Sie können es so versuchen.
Klasse mit Element-ID erstellen.
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;
}
}
Holen Sie sich jetzt diese Aufzählung mit id als int.
MyEnum myEnum = MyEnum.fromId(5);
Ich speichere die Werte zwischen und erstelle eine einfache statische Zugriffsmethode:
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
den gleichen Namen wie der Methode geben values()
. Ich benutze cachedValues
für Feldnamen.
Java-Enums haben nicht die gleiche Art von Enum-to-Int-Zuordnung wie in C ++.
Das heißt, alle Aufzählungen haben eine values
Methode, die ein Array möglicher Aufzählungswerte zurückgibt
MyEnum enumValue = MyEnum.values()[x];
sollte arbeiten. Es ist ein bisschen böse und es ist vielleicht besser, wenn möglich nicht zu versuchen, von int
s nach Enum
s (oder umgekehrt) zu konvertieren .
Dies ist normalerweise nicht der Fall, daher würde ich es mir noch einmal überlegen. Allerdings sind die grundlegenden Operationen: int -> enum using EnumType.values () [intNum] und enum -> int using enumInst.ordinal ().
Da jede Implementierung von values () keine andere Wahl hat, als Ihnen eine Kopie des Arrays zu geben (Java-Arrays sind niemals schreibgeschützt), sollten Sie eine EnumMap verwenden, um die Zuordnung enum -> int zwischenzuspeichern.
Hier ist die Lösung, mit der ich gehen möchte. Dies funktioniert nicht nur mit nicht sequentiellen Ganzzahlen, sondern sollte auch mit jedem anderen Datentyp funktionieren, den Sie möglicherweise als zugrunde liegende ID für Ihre Aufzählungswerte verwenden möchten.
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;
}
}
Ich muss IDs nur zu bestimmten Zeiten (beim Laden von Daten aus einer Datei) in Aufzählungen konvertieren, daher gibt es für mich keinen Grund, die Karte jederzeit im Speicher zu behalten. Wenn Sie möchten, dass auf die Karte jederzeit zugegriffen werden kann, können Sie sie jederzeit als statisches Mitglied Ihrer Enum-Klasse zwischenspeichern.
clearCachedValues
wenn Sie damit fertig sind (wodurch das private Feld wieder auf null gesetzt wird). Ich halte es für MyEnum.fromInt(i)
einfacher zu verstehen, als ein Kartenobjekt herumzugeben.
Falls es anderen hilft, verwendet die von mir bevorzugte Option, die hier nicht aufgeführt ist, die Kartenfunktion von 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);
}
}
Mit der Standardeinstellung, die Sie verwenden können null
, können throw IllegalArgumentException
oder können Sie fromInt
ein Optional
beliebiges Verhalten zurückgeben.
Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
getValue()
Methode definieren .
Sie können die values()
Aufzählung durchlaufen und den ganzzahligen Wert der Aufzählung mit dem folgenden Wert vergleichen 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
}
}
Und benutze einfach so:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
Ich hoffe das hilft;)
Basierend auf der Antwort von @ChadBefus und dem Kommentar von @shmosel würde ich empfehlen, dies zu verwenden. (Effiziente Suche und funktioniert mit reinem 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());
}
}
Eine gute Option ist es, die Konvertierung von int
nach zu vermeidenenum
: Wenn Sie beispielsweise den Maximalwert benötigen, können Sie x.ordinal () mit y.ordinal () vergleichen und x oder y entsprechend zurückgeben. (Möglicherweise müssen Sie Ihre Werte neu anordnen, um einen solchen Vergleich aussagekräftig zu machen.)
Wenn das nicht möglich ist, würde ich MyEnum.values()
in einem statischen Array speichern .
Dies ist die gleiche Antwort wie bei den Ärzten, zeigt jedoch, wie das Problem mit veränderlichen Arrays behoben werden kann. Wenn Sie diese Art von Ansatz aufgrund der Verzweigungsvorhersage zuerst verwenden, hat dies nur einen sehr geringen bis Null-Effekt und der gesamte Code ruft nur einmal veränderbare Array-Werte () auf. Da beide Variablen statisch sind, verbrauchen sie nicht bei jeder Verwendung dieser Aufzählung n * Speicher.
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;
}
}
}
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]
}
}
Verwendungszweck:
val status = Status.getStatus(1)!!
Schrieb diese Implementierung. Es ermöglicht fehlende und negative Werte und hält den Code konsistent. Die Karte wird ebenfalls zwischengespeichert. Verwendet eine Schnittstelle und benötigt Java 8.
Aufzählung
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);
}
}
Schnittstelle
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;
}
}