Was ist die Double Brace-Initialisierungssyntax ( {{ ... }}
) in Java?
java
initialization
double-brace-initialize
Sgokhales
quelle
quelle
Antworten:
Die Initialisierung mit doppelten Klammern erstellt eine anonyme Klasse, die von der angegebenen Klasse (den äußeren Klammern) abgeleitet ist, und stellt einen Initialisierungsblock innerhalb dieser Klasse (die inneren Klammern) bereit . z.B
Beachten Sie, dass die Verwendung dieser doppelten Klammerinitialisierung dazu führt, dass Sie anonyme innere Klassen erstellen. Die erstellte Klasse hat einen impliziten
this
Zeiger auf die umgebende äußere Klasse. Obwohl dies normalerweise kein Problem ist, kann es unter bestimmten Umständen zu Trauer führen, z. B. beim Serialisieren oder Sammeln von Müll, und es lohnt sich, sich dessen bewusst zu sein.quelle
Jedes Mal, wenn jemand eine Doppelklammerinitialisierung verwendet, wird ein Kätzchen getötet.
Abgesehen davon, dass die Syntax eher ungewöhnlich und nicht wirklich idiomatisch ist (Geschmack ist natürlich umstritten), verursachen Sie unnötigerweise zwei signifikante Probleme in Ihrer Anwendung, über die ich kürzlich hier ausführlicher gebloggt habe .
1. Sie erstellen viel zu viele anonyme Klassen
Jedes Mal, wenn Sie die doppelte Klammerinitialisierung verwenden, wird eine neue Klasse erstellt. ZB dieses Beispiel:
... wird diese Klassen produzieren:
Das ist ziemlich viel Aufwand für Ihren Klassenlader - für nichts! Natürlich dauert die Initialisierung nicht lange, wenn Sie dies einmal tun. Aber wenn Sie dies 20'000 Mal in Ihrer Unternehmensanwendung tun ... all diesen Heap-Speicher nur für ein bisschen "Syntaxzucker"?
2. Sie verursachen möglicherweise einen Speicherverlust!
Wenn Sie den obigen Code verwenden und diese Zuordnung von einer Methode zurückgeben, halten Aufrufer dieser Methode möglicherweise ahnungslos an sehr schweren Ressourcen fest, die nicht durch Müll gesammelt werden können. Betrachten Sie das folgende Beispiel:
Die zurückgegebene
Map
Datei enthält jetzt einen Verweis auf die einschließende Instanz vonReallyHeavyObject
. Sie wollen das wahrscheinlich nicht riskieren:Bild von http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/
3. Sie können so tun, als hätte Java Kartenliterale
Um Ihre eigentliche Frage zu beantworten, haben die Benutzer diese Syntax verwendet, um vorzutäuschen, dass Java so etwas wie Kartenliterale hat, ähnlich den vorhandenen Array-Literalen:
Einige Leute mögen dies syntaktisch anregend finden.
quelle
{{...}}
einemstatic
Feld initialisiert und als Feld deklariert wird, sollte es keinen möglichen Speicherverlust geben, nur eine anonyme Klasse und keine eingeschlossenen Instanzreferenzen, oder?Map.of()
diesen Zweck, so dass dies eine bessere Lösung sein wirdReallyHeavyObject
. Außerdem erfassen anonyme innere Klassen alle lokalen Variablen, die im Klassenkörper verwendet werden. Wenn Sie also nicht nur Konstanten verwenden, um Sammlungen oder Zuordnungen mit diesem Muster zu initialisieren, erfassen die Instanzen der inneren Klasse alle und referenzieren sie auch dann, wenn sie tatsächlich aus entfernt werden die Sammlung oder Karte. In diesem Fall benötigen diese Instanzen nicht nur doppelt so viel Speicher für die Referenzen, sondern weisen diesbezüglich einen weiteren Speicherverlust auf.Zum Beispiel:
Wie es funktioniert
Die erste Klammer erstellt eine neue anonyme innere Klasse. Diese inneren Klassen können auf das Verhalten ihrer übergeordneten Klasse zugreifen. In unserem Fall erstellen wir also tatsächlich eine Unterklasse der HashSet-Klasse, sodass diese innere Klasse die put () -Methode verwenden kann.
Und der zweite Satz von geschweiften Klammern ist nichts anderes als Instanzinitialisierer. Wenn Sie an Java-Kernkonzepte erinnern, können Sie statische Initialisiererblöcke aufgrund ähnlicher Klammern wie struct problemlos mit statischen Initialisierern verknüpfen. Der einzige Unterschied besteht darin, dass der statische Initialisierer mit dem Schlüsselwort static hinzugefügt und nur einmal ausgeführt wird. egal wie viele Objekte Sie erstellen.
Mehr
quelle
Eine unterhaltsame Anwendung der Doppelklammerinitialisierung finden Sie hier Dwemthys Array in Java .
Ein Ausschnitt
Und jetzt sei bereit für den
BattleOfGrottoOfSausageSmells
und… klobigen Speck!quelle
Ich denke, es ist wichtig zu betonen, dass es in Java keine "Double Brace-Initialisierung" gibt . Die Oracle-Website hat diesen Begriff nicht. In diesem Beispiel werden zwei Funktionen zusammen verwendet: anonyme Klasse und Initialisierungsblock. Scheint, als ob der alte Initialisierungsblock von den Entwicklern vergessen wurde und in diesem Thema einige Verwirrung stiftet. Zitat aus Oracle-Dokumenten :
Initialisierungsblöcke für Beispielvariablen sehen genauso aus wie statische Initialisierungsblöcke, jedoch ohne das statische Schlüsselwort:
quelle
1- Es gibt keine doppelten Klammern:
Ich möchte darauf hinweisen, dass es keine doppelte Klammerinitialisierung gibt. Es gibt nur einen normalen traditionellen Initialisierungsblock für eine Zahnspange. Der zweite Klammerblock hat nichts mit der Initialisierung zu tun. Antworten sagen, dass diese beiden Klammern etwas initialisieren, aber es ist nicht so.
2- Es geht nicht nur um anonyme Klassen, sondern um alle Klassen:
Fast alle Antworten sprechen davon, dass dies beim Erstellen anonymer innerer Klassen verwendet wird. Ich denke, dass Leute, die diese Antworten lesen, den Eindruck haben, dass dies nur beim Erstellen anonymer innerer Klassen verwendet wird. Aber es wird in allen Klassen verwendet. Das Lesen dieser Antworten scheint eine brandneue Besonderheit zu sein, die anonymen Klassen gewidmet ist, und ich denke, das ist irreführend.
3- Der Zweck besteht nur darin, Klammern nacheinander zu platzieren, nicht um ein neues Konzept:
In dieser Frage geht es um die Situation, in der sich die zweite öffnende Klammer unmittelbar nach der ersten öffnenden Klammer befindet. In der normalen Klasse gibt es normalerweise Code zwischen zwei geschweiften Klammern, aber es ist völlig dasselbe. Es geht also darum, Klammern zu setzen. Ich denke, wir sollten nicht sagen, dass dies eine neue aufregende Sache ist, denn dies ist die Sache, die wir alle kennen, sondern nur mit einem Code in Klammern geschrieben. Wir sollten kein neues Konzept namens "Double Brace Initialization" erstellen.
4- Das Erstellen verschachtelter anonymer Klassen hat nichts mit zwei geschweiften Klammern zu tun:
Ich stimme einem Argument nicht zu, dass Sie zu viele anonyme Klassen erstellen. Sie erstellen sie nicht als Initialisierungsblock, sondern nur, weil Sie sie erstellen. Sie würden auch dann erstellt, wenn Sie keine Initialisierung mit zwei geschweiften Klammern verwenden würden, sodass diese Probleme auch ohne Initialisierung auftreten würden ... Die Initialisierung ist nicht der Faktor, der initialisierte Objekte erstellt.
quelle
Um alle negativen Auswirkungen der Doppelklammerinitialisierung zu vermeiden, wie z.
mache die nächsten Dinge:
Beispiel:
Verwendungszweck:
Vorteile:
Nachteile:
Infolgedessen haben wir das einfachste Java Builder-Muster aller Zeiten.
Alle Beispiele finden Sie unter github: java-sf-builder-simple-example
quelle
Es ist unter anderem eine Verknüpfung zum Initialisieren von Sammlungen. Mehr erfahren ...
quelle
du meinst so etwas?
Es ist eine Array-Listen-Initialisierung in der Erstellungszeit (Hack)
quelle
Sie können einige Java-Anweisungen als Schleife einfügen, um die Sammlung zu initialisieren:
Dieser Fall wirkt sich jedoch auf die Leistung aus. Überprüfen Sie diese Diskussion
quelle
Wie von @Lukas Eder hervorgehoben, muss die Initialisierung von Sammlungen mit Doppelklammern vermieden werden.
Es wird eine anonyme innere Klasse erstellt, und da alle internen Klassen einen Verweis auf die übergeordnete Instanz behalten, kann - und wird dies zu 99% wahrscheinlich - die Garbage Collection verhindern, wenn auf diese Collection-Objekte mehr Objekte als nur das deklarierende referenziert werden.
Java 9 hat bequeme Methoden eingeführt
List.of
,Set.of
undMap.of
, die stattdessen verwendet werden soll. Sie sind schneller und effizienter als der Double-Brace-Initialisierer.quelle
Die erste Klammer erstellt eine neue anonyme Klasse und die zweite Klammer erstellt Instanzinitialisierer wie den statischen Block.
Wie andere darauf hingewiesen haben, ist die Verwendung nicht sicher.
Sie können diese Alternative jedoch immer zum Initialisieren von Sammlungen verwenden.
quelle
Dies scheint dasselbe zu sein wie das in Flash und VBScript so beliebte Schlüsselwort with. Es ist eine Methode, um zu ändern, was
this
ist und nichts weiter.quelle
this
ist. Die Syntax erstellt lediglich eine anonyme Klasse (daherthis
bezieht sich jeder Verweis auf das Objekt dieser neuen anonymen Klasse) und verwendet dann einen Initialisierungsblock{...}
, um die neu erstellte Instanz zu initialisieren.