Enum überschreitung der 65535 Byte-Grenzwert der statischen Initialisierer,... was am besten zu tun ist?
Ich angefangen habe, ein ziemlich großes Enum-der so genannte Deskriptoren, die ich haben wollte, zu verwenden, als eine Referenz-Liste in meinem Modell. Aber jetzt bin ich gekommen über einen compiler/VM-Grenze das erste mal und ich bin auf der Suche nach der besten Lösung, um diese zu bewältigen.
Hier ist mein Fehler : den code für Die statische Initialisierer ist eine überschreitung der 65535 Byte-Grenzwert
Es ist klar, wo diese herkommt - mein Enum hat einfach viel zu viele Elemente. Aber ich brauche diese Elemente - es gibt keinen Weg, um diese zu reduzieren setzen.
Erstmal habe ich geplant, um die Verwendung einer einzigen Enum-weil ich will, um sicherzustellen, dass alle Elemente innerhalb des Enum-sind einzigartig. Es ist in einem Hibernate Persistenz-Kontext, wo der Verweis auf das Enum gespeichert ist, als Zeichenfolge in der Datenbank. Also das muss eindeutig sein!
Den Inhalt meiner Enum kann aufgeteilt werden in mehrere Gruppen von Elementen, die gehören zusammen. Aber die Aufteilung der Enum entfernen würde, die einzigartige Sicherheit, die ich während der Kompilierung. Oder kann das erreicht werden mit mehreren Enums in irgendeiner Weise?
Nur meine aktuelle Idee ist die Definition einer Schnittstelle namens Deskriptor und code mehrere Enums implementieren. Auf diese Weise hoffe ich, in der Lage sein, um die Verwendung der Hibernate-Enum-mapping, als ob es einer einzigen Enum. Aber ich bin mir auch nicht sicher, ob dies funktionieren wird. Und ich löse einzigartige Sicherheit.
Irgendwelche Ideen, wie Griff, Fall?
- Siehe meine Antwort auf diese Frage: stackoverflow.com/a/27515185/768795
Du musst angemeldet sein, um einen Kommentar abzugeben.
Einfach. Verwenden Sie nicht
enum
für diese. Das können Sie nicht. Es wird nicht funktionieren.Sind die Chancen, dass Ihr Quellcode nicht explizit Bezug auf viele der enum-Werte. Vielmehr sind Sie mit dem enum als ein bequemer Weg, um die Zuordnung zwischen Objekt-Instanzen und string als Namen. So ersetzen Sie einfach den enum-Typ mit einem Typ, der explizit verwaltet die Zuordnung initialisieren durch das Lesen aus einer Datei oder Datenbank. Wenn Sie es richtig machen, erhalten Sie die rechnerische Eigenschaften und Typ-Sicherheit von enum. Das einzige, was Sie verlieren, ist der syntaktische Zucker ... und der Statik.
Dieser Ansatz hätte den zusätzlichen Vorteil, dass Sie ändern können, die "Deskriptoren" mapping ohne änderungen am Quellcode des Programms.
Durch die Art und Weise, die Begrenzung, Sie laufen in die von der JVM-class-file-format. Eine Methode oder ein Konstruktor hat eine Obere Größenbeschränkung von 2^16 bytes, und ein Klassen statische Initialisierungs-code wird dargestellt als eine spezielle Methode mit einer funky Namen.
UPDATE
Leider Ihr selbst beantworten, die Lösung wird immer noch laufen in ein anderes 64K-limit ... wenn geschoben zu weit. Die Aufteilung der
initialize()
- Methode wird um die Methode size limit, aber es gibt auch eine 64 Kb-limit auf die Anzahl der Einträge in den a-Klassen Konstanten-pool. Jedes String-literal erfordert ein Konstanten-pool-Eintrag.enum
per se, weil Sie nicht den enum-Namen in den Quell-code.Dies ist nicht eine einfache Lösung, aber Sie können versuchen... patch der Java-compiler.
Wenn Sie schreiben eine
enum
, die Java-compiler-erzeugen einer Klasse, die erweitertjava.lang.Enum
(eventuell mehrere Klassen, wenn es konstant-spezifische Methoden). Die Klasse hat einige (versteckte) statische Felder, die auf der bytecode-Ebene initialisiert werden mit dem speziellen<clinit>()
Methode (die JVM ruft, wenn die Klasse das erste mal verwendet wird). Wie jede andere Methode, die den code für die<clinit>()
- Methode ist begrenzt auf 65535 bytes. Jede Konstante trägt zu etwa 20 bis 22 bytes in den<clinit>()
bytecode (oder mehr, wenn es Konstanten spezifischen Konstruktoren), Sie schlagen also die Grenze, an der über 3000 enumeration-Konstanten.Nun die
<clinit>()
Methode hat einen komischen Namen, aber es ist nichts wirklich besonderes; es kann den Aufruf anderer Methoden. Der Java-compiler könnte split mammoth<clinit>()
in mehrere versteckte sub-Methoden, die<clinit>()
ruft dann einer nach dem anderen. Der Java-compiler derzeit nicht tun, aber theoretisch könnte. Das Ergebnis wäre auch von jedem JRE.Alternativ, synthetisieren Ihre enum-Klasse synthetisch, generieren von bytecode von einem speziellen Programm, möglicherweise selbst in Java geschrieben. Im wesentlichen, dies ist, wie das schreiben Ihre eigenen, spezialisierten compiler, für eine bestimmte Ziel-und mit Ihren eigenen Quellcode-syntax. Die BCEL Bibliothek kann helfen.
Beachten Sie, dass es andere Grenzen, die könnte auf Sie springen. Für jede enumeration-Konstanten, statischen code (der in
<clinit>()
) verwendet zwei "Konstanten", die interne aggregierte Werte in der "constant pool" Teil der kompilierten Klasse. Die beiden Werte sind die Konstanten Namen (als string) und den daraus resultierenden statischen Feld Referenz. Es ist eine harte Begrenzung auf 65536 Konstanten-pool-Einträge (Indizes sind auf 16 bits), also nicht mehr als ein bisschen mehr als 32000 enumeration-Konstanten. Eine gepatchte Java-compiler um gehen konnte, die Grenze durch die Generierung mehrerer hidden-Klassen, jede mit Ihrer eigenen Konstanten-pool. Eine härtere Grenze ist die Anzahl der statischen Felder: jede enumeration-Konstanten wird ein statisches Feld in der "enum" - Klasse, und es können nicht mehr als 65535 Felder (statisch oder nicht) in eine Klasse.Können Sie versuchen, die typesafe enum pattern
beschrieben von Joshua Bloch in der ersten Ausgabe von seinem Buch "Effective Java".
Die Idee ist, erstellen Sie eine Klasse mit einem privaten Konstruktor. Innerhalb dieser Klasse definieren Sie statische Instanzen von jeder Zahl, die Sie möchten-genau wie im Java-enum.
Ich weiß nicht, ob es ein limit für die Anzahl der statischen Elemente in der Java-Sprache, obwohl.
Könnten Sie versuchen, die Verschachtelung statische innere Klassen, die innerhalb einer top-level-Klasse
Meine ursprüngliche Idee war die Karte die Enum mit der @Enumerated Kommentar. Dies würde ausgesehen haben, wie im folgenden Beispiel:
Würde die Datenbank eine Spalte " DESKRIPTOR-Typ varchar und im Ruhezustand (in meinem Fall) würde die Karte die Zeichenfolge in die Aufzählung.
Aber ich habe das limit von 65k (siehe Frage), das ist zu klein in meinem Fall. Aber ich habe eine Lösung gefunden. Haben Sie einen Blick auf das folgende Beispiel:
Diesem Deskriptor-Klasse simuliert die Verwendung eines typischen enum. Aber jetzt bin ich in der Lage, teilen Sie die initialize () - Methode in mehrere diejenigen, die arbeiten rund um die 65k Grenze, besteht auch für Methoden. Die Enum nicht erlauben, teilen Sie die Initialisierung in mehrere Stücke - meiner Klasse.
Nun, ich habe mit einer etwas anderen Zuordnung jedoch:
Diese Weise kann ich die Klasse verwenden, wie ein Enum in den meisten Fällen. Es ist ein bisschen schwierig... aber es scheint zu funktionieren. Vielen Dank für all den input, die schließlich führte mich zu dieser Lösung.