Kann ich Aufzählungselemente zur Laufzeit in Java hinzufügen und entfernen
Lesezeit: 7 Minuten
brabster
Ist es möglich, zur Laufzeit Elemente aus einer Aufzählung in Java hinzuzufügen und zu entfernen?
Könnte ich beispielsweise die Labels und Konstruktorargumente einer Aufzählung aus einer Datei einlesen?
@saua, es ist nur die Frage, ob man das wirklich aus Interesse machen kann. Ich hatte gehofft, es gäbe eine nette Möglichkeit, den laufenden Bytecode zu ändern, vielleicht mit BCEL oder so. Ich bin dieser Frage auch nachgegangen, weil mir klar wurde, dass ich nicht ganz sicher war, wann eine Aufzählung verwendet werden sollte.
Ich bin ziemlich davon überzeugt, dass die richtige Antwort darin besteht, anstelle einer Aufzählung eine Sammlung zu verwenden, die die Eindeutigkeit gewährleistet, wenn ich den Inhalt sicher zur Laufzeit ändern möchte.
Wenn Sie dies wollen, missbrauchen Sie sie normalerweise. Können Sie uns sagen, wofür Sie das brauchen?
– Joachim Sauer
26. Januar 09 um 0:05 Uhr
Meine Antwort wurde mit einer HashMap hinter den Kulissen implementiert, sodass Sie die Eindeutigkeit sicherstellen können.
– moffdub
27. Januar 09 um 11:44 Uhr
FWIW, es hilft beim Testen von Standardfällen für das Einschalten von Enumerationen.
– Daniel C. Sobral
27. Juli 16 um 6:31 Uhr
Tom Hawtin – Tackline
Nein, Aufzählungen sollen eine vollständige statische Aufzählung sein.
Zur Kompilierzeit möchten Sie vielleicht Ihre Enum-Java-Datei aus irgendeiner anderen Quelldatei generieren. Sie könnten sogar eine .class-Datei wie diese erstellen.
In einigen Fällen möchten Sie möglicherweise einen Satz von Standardwerten, lassen aber eine Erweiterung zu. Der übliche Weg, dies zu tun, ist ein interface für die Schnittstelle und ein enum der das umsetzt interface für die Standardwerte. Natürlich verliert man die Fähigkeit dazu switch wenn Sie nur einen Verweis auf die haben interface.
Würden Sie wissen, wo ich ein gutes Beispiel für eine Aufzählung finden kann, die eine solche Schnittstelle implementiert? Ich werde an einer solchen Funktionalität interessiert sein.
– megalucio
19. Oktober 17 um 15:10 Uhr
@megalucio Ich glaube, ich dachte an java.nio.file.StandardOpenOptiondocs.oracle.com/javase/8/docs/api/java/nio/file/… aber es gibt auch java.net.StandardProtocolFamily und javax.tools.StandardLocation.
– Tom Hawtin – Angelleine
20. Oktober 17 um 21:54 Uhr
Vielen Dank . Ich werde mir das mal anschauen.
– megalucio
23. Oktober 17 um 16:51 Uhr
Yuval
Hinter dem Vorhang sind Enumerationen POJOs mit einem privaten Konstruktor und einer Reihe öffentlicher statischer Endwerte des Typs der Enumeration (siehe Hier zum Beispiel). Tatsächlich galt es bis Java5 als bewährte Methode, Ihre eigene Aufzählung auf diese Weise zu erstellen, und Java5 führte die enum Schlüsselwort als Kurzform. Siehe die Quelle für Enum um mehr zu lernen.
Es sollte also kein Problem sein, ein eigenes ‘TypeSafeEnum’ mit einem öffentlichen statischen endgültigen Array von Konstanten zu schreiben, die vom Konstruktor gelesen oder an ihn übergeben werden.
Tun Sie sich auch selbst einen Gefallen und überschreiben Sie equals, hashCode und toStringund wenn möglich erstellen Sie eine values Methode
Die Frage ist, wie man eine solche dynamische Aufzählung verwendet … Sie können den Wert “PI = 3.14” nicht aus einer zu erstellenden Datei lesen enum MathConstants und dann weitermachen und verwenden MathConstants.PI wo immer Sie wollen…
Schreiben Sie niemals ein öffentliches statisches nicht leeres Array-Feld – sie sind nicht konstant.
– Tom Hawtin – Angelleine
25. Januar 09 um 22:37 Uhr
Ist das wahr? Da die Instanz am Ende der Referenz unveränderlich ist, bin ich mir nicht sicher, wie Sie sie tatsächlich ändern könnten … sind es nur gekreuzte Drähte, ob es sich um eine Array-Instanz handelt oder nicht?
– Brabster
26. Januar 09 um 20:13 Uhr
Sammlungen und Arrays sind beide veränderliche Objekte (und “Objekte”). Ein “endgültiges” Array zu haben bedeutet nur, dass Sie die Größe des Arrays nicht ändern oder anderweitig neu zuweisen werden, aber Sie können trotzdem Werte ersetzen, die bereits in seine Grenzen passen.
Es ermöglicht das Hinzufügen, Entfernen und Wiederherstellen von Enum-Werten.
Bearbeiten: Ich habe gerade erst damit begonnen und festgestellt, dass für Java 1.5 einige geringfügige Änderungen erforderlich sind, an denen ich derzeit festhalte:
Mein Ansatz bestand darin, die Werte und Namen der Aufzählung extern zu speichern, und das Endziel bestand darin, Code schreiben zu können, der einer Sprachenaufzählung so ähnlich wie möglich war.
Ich wollte, dass meine Lösung so aussieht:
enum HatType
{
BASEBALL,
BRIMLESS,
INDIANA_JONES
}
HatType mine = HatType.BASEBALL;
// prints "BASEBALL"
System.out.println(mine.toString());
// prints true
System.out.println(mine.equals(HatType.BASEBALL));
Und ich endete mit etwas in der Art:
// in a file somewhere:
// 1 --> BASEBALL
// 2 --> BRIMLESS
// 3 --> INDIANA_JONES
HatDynamicEnum hats = HatEnumRepository.retrieve();
HatEnumValue mine = hats.valueOf("BASEBALL");
// prints "BASEBALL"
System.out.println(mine.toString());
// prints true
System.out.println(mine.equals(hats.valueOf("BASEBALL"));
Da meine Anforderungen darin bestanden, dass Mitglieder zur Laufzeit zur Aufzählung hinzugefügt werden können, habe ich diese Funktionalität ebenfalls implementiert:
Der Unterschied zwischen den beiden besteht darin, dass die überarbeitete Ausgabe entworfen wurde, nachdem ich wirklich angefangen hatte, OO und DDD zu groken. Das erste, das ich entworfen habe, als ich noch nominell prozedurale DDD geschrieben habe, nicht weniger unter Zeitdruck.
Sie können eine Java-Klasse zur Laufzeit aus der Quelle laden. (Mit JCI, BeanShell oder JavaCompiler)
Auf diese Weise können Sie die Enum-Werte nach Belieben ändern.
Hinweis: Dies würde keine Klassen ändern, die sich auf diese Aufzählungen beziehen, daher ist dies in der Realität möglicherweise nicht sehr nützlich.
Ein weit verbreitetes Arbeitsbeispiel ist das modifizierte Minecraft. Siehe EnumHelper.addEnum()-Methoden auf GitHub
Beachten Sie dies jedoch in seltenen Situationen Die praktische Erfahrung hat gezeigt, dass das Hinzufügen von Enum-Mitgliedern zu einigen Problemen mit dem JVM-Optimierer führen kann. Die genauen Probleme können je nach JVM variieren. Aber im Großen und Ganzen scheint der Optimierer davon auszugehen, dass einige interne Felder eines Enums, insbesondere die Größe des Enums, davon ausgehen .values() Array, wird sich nicht ändern. Sehen Themendiskussion. Die empfohlene Lösung gibt es nicht zu machen .values() ein Hotspot für den Optimierer. Wenn also zur Laufzeit Mitglieder einer Enum hinzugefügt werden, sollte dies einmal und nur einmal erfolgen, wenn die Anwendung initialisiert wird, und dann das Ergebnis von .values() sollte zwischengespeichert werden, um zu vermeiden, dass es zu einem Hotspot wird.
Die Funktionsweise des Optimierers und die Art und Weise, wie er Hotspots erkennt, ist unklar und kann zwischen verschiedenen JVMs und verschiedenen Builds der JVM variieren. Wenn Sie das Risiko dieser Art von Problemen im Produktionscode nicht eingehen möchten, ändern Sie Enums nicht zur Laufzeit.
Eldelshell
Sie könnten versuchen, der ENUM, die Sie erstellen möchten, Eigenschaften zuzuweisen und sie mithilfe einer geladenen Eigenschaftendatei statisch zu erstellen. Großer Hack, aber es funktioniert 🙂
.
7576800cookie-checkKann ich Aufzählungselemente zur Laufzeit in Java hinzufügen und entfernenyes
Wenn Sie dies wollen, missbrauchen Sie sie normalerweise. Können Sie uns sagen, wofür Sie das brauchen?
– Joachim Sauer
26. Januar 09 um 0:05 Uhr
Meine Antwort wurde mit einer HashMap hinter den Kulissen implementiert, sodass Sie die Eindeutigkeit sicherstellen können.
– moffdub
27. Januar 09 um 11:44 Uhr
FWIW, es hilft beim Testen von Standardfällen für das Einschalten von Enumerationen.
– Daniel C. Sobral
27. Juli 16 um 6:31 Uhr