Die Klassenvariablen werden beim Laden einer Klasse gesetzt. JVMs laden ihre Klassen fast immer erst dann, wenn das erste Mal eine Operation an ihnen aufgerufen oder auf ein Feld bei Ihnen zugegriffen wird. Bei einem Singleton bedeutet dies, dass die Klasse meist erst dann geladen - und damit auch erst ein Exemplar erzeigt - wird, wenn man getInstance() daran aufruft. D.h. wenn man die Initialisierung in getInstance() macht, ist sie nur minimal später, als wenn man sie direkt in der Intialisierung der Klassenvariable macht. Deswegen meine ich, dass dies nur eine scheinbar verzögerte Initialisierung ist: Sie ist praktisch nicht verzögert.
Richtiggehend "schlecht" ist eine Initialisierung in getInstance() zwar auch nicht, aber sie benötigt eine Synchronisation und eine if-Anweisung in jedem Zugriff. Die Synchronisation ist in heutigen JVMs auch nicht mehr so schmerzhaft, wie sie es mal beim jdk 1.0 war, aber sie ist eben dennoch da und könnte sich ggf. mit einer anderen Synchronisation an der selben Klasse beißen. Die If-Anweisung kostet ebenfalls nicht die Welt, aber man kann den Sourcecode eben auch einfacher gestalten, ohne dass es einem weh tut.
Oder? Tut einem die Initialisierung direkt an der Definition der Klassenvariable wirklich nicht weh? Doch, es gibt da Szenarien: Zum einen ist das verzögerte Laden der Klassen in JVMs zwar heute absoluter Standard, aber verlassen kann man sich darauf nicht. Zum anderen gibt es eben doch den Fall (insbesondere bei kreisförmigen) Abhängigkeiten, dass eine Initialisierung nicht schon beim Laden der Klasse geschehen darf.
Der zweite Fall begegnet mir
äußerst selten. Den ersten Fall sehe ich etwas kritischer, denn man sollte mit solchen Annahmen vorsichtig sein. Allerdings muß man betrachten, welche Folgen es hat, wenn die Annahme der verzögerten Initialisierung durch verzögertes Klassenladen nicht mehr zutrifft: In den allermeisten Fällen bedeutet dies nur, dass ein paar wenige Objekte früher als nötig erzeugt werden. Sehr selten erlebe ich es, dass die Singleton-Objekte knappe Resourcen in so großem Ausmaß belegen, dass dies ein frühe Initialisierung des Objektes zu einem Desaster werden ließe.
Deswegen mache ich eine später Initialisierung in getInstance() wirklich nur in den seltenen Fällen, wenn die Initialisierung sehr teuer ist oder sie beim Laden der Klasse Probleme macht. (OK, genaugenommen vermeide ich heutzutage Singeltons sowieso an vielen Stellen, da sie oft unnötig sind und einem bei Tests öfter mal im Weg sind, wenn man das Singleton durch ein Testobjekt ersetzen will.)
Ach, ja, zu dem Anonymen: Syncronized ist nötig, wenn man zusichern will, dass wirklich nur ein Exemplar des Singletons erzeugt wird. Sonst könnten zwei Threads gleichzeitig "getInstance()" aufrufen und in instance null vorfinden.
Und falls es jemand noch nicht gehört hat:
Double checked locking ist auch keine clevere Lösung, sondern
böse.
LEIFer