Versuchen Sie, MyEnum.values()[x]wo sein xmuss 0oder 1dh 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 intoder sogar Integerkeine Aufzählung umwandeln können.
+1: Möglicherweise möchten Sie zwischenspeichern, MyEnum.values()da dies teuer ist. dh wenn Sie es hunderte Male nennen.
Peter Lawrey
6
@ PeterLawrey Kannst du der Vollständigkeit halber erklären, warum es langsam sein sollte? Ich sehe keinen offensichtlichen Grund dafür.
Tarrasch
48
@Tarrasch Da Arrays veränderbar sind, muss values () eine Kopie des Arrays von Elementen zurückgeben, nur für den Fall, dass Sie es ändern. Das Erstellen dieser Kopie ist jedes Mal relativ teuer.
Peter Lawrey
9
@ PeterLawrey Ich habe in letzter Zeit zu viel Haskell verwendet (wo alles unveränderlich ist)! Vielen Dank für Ihre klare und präzise Erklärung. :)
Tarrasch
Wie bekomme ich das 'x'?
Beeing Jk
160
MyEnum.values()[x]ist eine teure Operation. Wenn die Leistung ein Problem darstellt, möchten Sie möglicherweise Folgendes tun:
Wenn Sie die Switch-Wartung vermeiden möchten, verwenden Sie die using-Klasse: private final MyEnum [] myEnumValues = MyEnum.values (); Dann Verwendung: myEnum = myEnumValues [i];
Gili Nachum
23
@GiliNachum sagte es auf seltsame Weise, aber das Problem mit dieser Lösung ist die Wartbarkeit. Dies verstößt gegen das DRY-Prinzip, dh, wenn die Aufzählungswerte geändert werden (neu angeordnet, Wert (e) hinzugefügt, Wert (e) entfernt), muss die switch-Anweisung gleichzeitig aktualisiert werden. Gilis Kommentar zwingt Java, die Konsistenz mit der Liste der Aufzählungswerte aufrechtzuerhalten. Änderungen an den Aufzählungswerten wirken sich überhaupt nicht auf diesen Ansatz aus.
Dandre Allison
3
@ LorenzoPolidori, können Sie erklären, warum Sie 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.
Brunsgaard
1
@brunsgaard Ich gehe davon 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.
MikeFHay
1
Die Version von @Johnson Gili erfordert keine zusätzlichen Codeänderungen außerhalb der Änderungen in der Enum-Deklaration. Wenn Sie der Aufzählung ein neues Element hinzufügen, myEnum = myEnumValues[i]wird das idritte Element in der Aufzählung ohne Änderungen zurückgegeben.
Dandre Allison
45
Wenn Sie Ihre ganzzahligen Werte angeben möchten, können Sie eine Struktur wie die folgende verwenden
publicenum A
{
B(0),
C(10),None(11);int id;private A(int i){id = i;}publicintGetID(){return id;}publicbooleanIsEmpty(){returnthis.equals(A.None);}publicbooleanCompare(int i){return id == i;}publicstatic A GetValue(int _id){
A[]As= A.values();for(int i =0; i <As.length; i++){if(As[i].Compare(_id))returnAs[i];}return A.None;}}
+1, weil es die Tatsache hervorhebt, dass Werte nicht aufeinanderfolgend sein müssen.
Rhavin
Dies scheint auch die einzige Antwort zu sein, die funktioniert, wenn Sie einen spärlichen (oder wiederholten) Satz ganzzahliger Werte wünschen, anstatt die Standard-Ordnungszahlen von 0 .. (count-1) zu verwenden. Dies kann wichtig sein, wenn Sie mit vorhandenem Code interagieren, z. B. über ein Netzwerk.
Benkc
Es sei darauf hingewiesen, dass es sich wie in den obigen Antworten wahrscheinlich lohnt, das Ergebnis von values () zwischenzuspeichern, um bei jedem Aufruf eine Speicherzuweisung und Arraykopie zu vermeiden.
Benkc
1
Abhängig von der Länge Ihrer Aufzählung möchten Sie möglicherweise eine HashMap erstellen oder eine binäre Suche oder etwas anderes für diese Suche verwenden, anstatt jedes Mal eine lineare Suche durchzuführen.
Benkc
2
Dies sollte der richtige Weg und die beste Vorgehensweise sein, um int in enum zu konvertieren, und ich denke, Sie können das Problem durch öffentliche statische A GetValue (int _id) {für (A a: A.values () {if (a.getId () vereinfachen ) == _ id) {return a;}} return null;} Werde das None los, isEmpty () und vergleiche () Zeug.
Chris.Zou
35
Sie können es so versuchen.
Klasse mit Element-ID erstellen.
publicEnumMyEnum{
THIS(5),
THAT(16),
THE_OTHER(35);privateint id;// Could be other data type besides intprivateMyEnum(int id){this.id = id;}publicstaticMyEnum fromId(int id){for(MyEnum type : values()){if(type.getId()== id){return type;}}returnnull;}}
Holen Sie sich jetzt diese Aufzählung mit id als int.
Dies ist eine Lösung, die ich jetzt benutze. Aber meiner Meinung nach ist es weniger verwirrend, wenn Sie dem Feld nicht valuesden gleichen Namen wie der Methode geben values(). Ich benutze cachedValuesfür Feldnamen.
ToolmakerSteve
2
Effizient und elegant; kopiert und in mein Projekt eingefügt :) Das einzige, was ich geändert habe, ist fromInt (int i), das ich gerade von (int i) aufgerufen habe, weil es etwas redundant ist, int zweimal in der Signatur zu haben.
Pipedreambomb
1
Warum nicht von Anfang an initialisieren? Warum auf den ersten Treffer warten?
Kaiser
9
Java-Enums haben nicht die gleiche Art von Enum-to-Int-Zuordnung wie in C ++.
Das heißt, alle Aufzählungen haben eine valuesMethode, 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 ints nach Enums (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.
Betreff "Dies ist normalerweise nicht der Fall": Häufiger Fall, in dem dies nützlich ist: enum entspricht int-Werten, die in einer Datenbank gespeichert sind.
ToolmakerSteve
@ToolmakerSteve Sie haben absolut Recht, dass die Zuordnungen erforderlich sind. Aber möchten Sie diese Art der Codierung einem OR-Mapper oder einem Toolkit / einer Bibliothek überlassen?
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.
publicEnumMyEnum{
THIS(5),
THAT(16),
THE_OTHER(35);privateint id;// Could be other data type besides intprivateMyEnum(int id){this.id = id;}publicint getId(){returnthis.id;}publicstaticMap<Integer,MyEnum> buildMap(){Map<Integer,MyEnum> map =newHashMap<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.
IMHO, wenn ich über die Speichernutzung besorgt wäre, würde ich die HashMap dynamisch erstellen - wie @ossys, aber mit unterschiedlichem Code, wenn der Cache null ist, und dann eine zweite Methode hinzufügen, clearCachedValueswenn 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.
ToolmakerSteve
6
Falls es anderen hilft, verwendet die von mir bevorzugte Option, die hier nicht aufgeführt ist, die Kartenfunktion von Guava :
Mit der Standardeinstellung, die Sie verwenden können null, können throw IllegalArgumentExceptionoder können Sie fromIntein Optionalbeliebiges Verhalten zurückgeben.
Sie sollten erwähnen, dass Sie Guava verwenden. Oder Sie können Streams verwenden:Map<Integer, MyEnum> reverseLookup = Arrays.stream(MyEnum.values()).collect(Collectors.toMap(MyEnum::getValue, Function.identity()));
Shmosel
1
Vielleicht möchten Sie auch eine getValue()Methode definieren .
Shmosel
@shmosel Ups, ich habe die Funktion getValue verpasst, danke. Das Eingeben generischer Versionen in den Stackoverflow wird nicht immer ausgeführt. Kommentar zur Verwendung von Guava mit einem Link hinzugefügt. Ziehen Sie die Guava-Methode Streams vor.
Chad Befus
3
Sie können die values()Aufzählung durchlaufen und den ganzzahligen Wert der Aufzählung mit dem folgenden Wert vergleichen id:
publicenumTestEnum{None(0),Value1(1),Value2(2),Value3(3),Value4(4),Value5(5);privatefinalint value;privateTestEnum(int value){this.value = value;}publicint getValue(){return value;}publicstaticTestEnum getEnum(int value){for(TestEnum e:TestEnum.values()){if(e.getValue()== value)return e;}returnTestEnum.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)
Eine gute Option ist es, die Konvertierung von intnach 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 .
Wenn Sie int von DB erhalten und es in Enum konvertieren möchten, was meiner Meinung nach eine sehr häufige Aufgabe ist, benötigen Sie int -> enum-Konvertierung, IMO ..
Yuki Inoue
0
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.
privatestaticboolean arrayCreated =false;privatestaticRFMsgType[]ArrayOfValues;publicstaticRFMsgTypeGetMsgTypeFromValue(intMessageID){if(arrayCreated ==false){ArrayOfValues=RFMsgType.values();}for(int i =0; i <ArrayOfValues.length; i++){if(ArrayOfValues[i].MessageIDValue==MessageID){returnArrayOfValues[i];}}returnRFMsgType.UNKNOWN;}
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.
Antworten:
Versuchen Sie,
MyEnum.values()[x]
wo seinx
muss0
oder1
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 sogarInteger
keine Aufzählung umwandeln können.quelle
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:quelle
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 dasi
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
quelle
Sie können es so versuchen.
Klasse mit Element-ID erstellen.
Holen Sie sich jetzt diese Aufzählung mit id als int.
quelle
Ich speichere die Werte zwischen und erstelle eine einfache statische Zugriffsmethode:
quelle
values
den gleichen Namen wie der Methode gebenvalues()
. Ich benutzecachedValues
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ückgibtsollte arbeiten. Es ist ein bisschen böse und es ist vielleicht besser, wenn möglich nicht zu versuchen, von
int
s nachEnum
s (oder umgekehrt) zu konvertieren .quelle
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.
quelle
Verwenden
MyEnum enumValue = MyEnum.values()[x];
quelle
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.
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.
quelle
clearCachedValues
wenn Sie damit fertig sind (wodurch das private Feld wieder auf null gesetzt wird). Ich halte es fürMyEnum.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 :
Mit der Standardeinstellung, die Sie verwenden können
null
, könnenthrow IllegalArgumentException
oder können SiefromInt
einOptional
beliebiges Verhalten zurückgeben.quelle
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 vergleichenid
:Und benutze einfach so:
TestEnum x = TestEnum.getEnum(4);//Will return TestEnum.Value4
Ich hoffe das hilft;)
quelle
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)
quelle
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 .quelle
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.
quelle
quelle
In Kotlin:
Verwendungszweck:
quelle
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
Schnittstelle
quelle