Wie vermeide ich Probleme beim Zugriff auf statische Felder vor der Initialisierung der Klasse?

8

Ich habe diesen Code:

%Vor%

Ich weiß, es sieht so aus, als sollte es ein enum sein, und das wäre es, aber es muss von Person, einer abstrakten Klasse, übernommen werden.

Mein Problem ist: Wenn ich versuche, auf die Liste der Jungs zuzugreifen, geht es mir gut. Aber ich versuche auf irgendeinen Guy zuzugreifen, ich habe ein Problem: Guy wird vor Person geladen. Da Guy jedoch Person erbt, wird Person geladen und versucht, auf TOM zuzugreifen, aber da Guy bereits geladen wird, kann der Ladevorgang nicht erneut gestartet werden. Daher haben wir eine Null Referenz. (Und ImmutableList akzeptiert keine Null, daher erhalten wir eine Ausnahme.)

Ich weiß also warum das passiert, aber ich bin nicht sicher, wie ich es vermeiden kann. Ich könnte die Liste in die Klasse Guy verschieben, aber ich habe mehr als eine Implementierung von Person , und ich hätte gerne eine Master-Liste aller Person s in der Klasse Person / p>

Es kommt mir seltsam vor, dass es möglich ist, eine statische innere Klasse zu laden, ohne ihre enthaltene Klasse zu laden, aber ich denke, es macht Sinn. Gibt es eine Möglichkeit, dieses Problem zu lösen?

    
codebreaker 14.05.2015, 23:27
quelle

4 Antworten

3

Sie könnten Ihre unveränderbare Liste in einer separaten Klasse wie People.GUYS :

behalten %Vor%

Auf diese Weise können Sie die einzelnen Jungs in der Klasse Guy behalten:

%Vor%     
Dmitry Grigoryev 14.05.2015, 23:55
quelle
2

Eine Lösung um der Lösung willen funktioniert das (für einen einzelnen Thread)

%Vor%

OPs Design ist von Natur aus rekursiv. Obwohl Java über eine wohldefinierte Initialisierungsprozedur verfügt (die zurückgeht, wenn die Rekursion erkannt wird), hängt das Verhalten davon ab, welche Klasse zuerst initialisiert wird.

Das Problem wird durch die Anforderung, dass die Felder final sind, verschlechtert, was die Zuweisung stark einschränkt. Andernfalls können wir if(null) assign an mehreren Stellen versuchen, um das Problem zu lösen.

Die oben beschriebene Lösung verwendet im Wesentlichen eine temporäre Variable, um die final Einschränkung zu umgehen.

Eine modifizierte Version mit einer Map, die für eine größere Anzahl von Feldern geeignet ist:

%Vor%

Mehrfachgewinde

Es ist möglich, dass ein Thread die Person initialisiert, während ein anderer Thread Guy initialisiert. Deadlock ist möglich, und es passiert in der realen Welt. Daher ist dieses Design inhärent fehlerhaft.

Im Allgemeinen besteht bei zwei Klassen (nicht notwendigerweise Eltern-Kind), die während der statischen Initialisierung voneinander abhängig sind, die Gefahr eines Deadlocks.

Die Anwendung kann so etwas durchmachen, indem sie die Initialisierung beim Programmstart sorgfältig startet. Trotzdem ist das ziemlich gefährlich, und es könnte jemanden in Tage des Debuggens der Hölle schicken.

    
ZhongYu 14.05.2015 23:45
quelle
1

Soll die absolute Klasse Person abstract verwendet werden (d. h. ist sie bereits Teil des Legacy-Codes)?

Wenn nicht, dann empfehle ich Ihnen, das Design Ihres Datenmodells in eine Guy enum -Klasse umzuwandeln, die eine Person-Schnittstelle implementiert. Es gibt viele Vorteile gegenüber dem klassenbasierten Design.

%Vor%

Beachten Sie, dass es in diesem Fall keinen Grund gibt, eine List -Instanz mit den konstanten Referenzen zu definieren, da die enum-API die GUY.values() -Methode bereitstellt.

Es würde alle Ihre Initialisierungsfehler lösen und trotzdem mehrere Implementierungen von Person ermöglichen. Der Nachteil ist die Code-Duplizierung. Die Methoden in Person müssen in jeder enum-Klasse implementiert werden (wenn es jedoch viele Methoden gibt, können Sie immer eine private statische Hilfsklasse erstellen und Methodenaufrufe an sie weiterleiten.)

    
scottb 15.05.2015 01:28
quelle
1

ändern

%Vor%

bis

%Vor%

sollte funktionieren (ich habe mit JDK 8 getestet), aber erfüllt es immer noch Ihre Anforderung?

%Vor%     
diufanman 15.05.2015 09:13
quelle

Tags und Links