Statische Initialisierungen Und Statische Methoden In Java
Tut, Aufruf einer statischen Methode einer Klasse in Java auslösen der statischen Initialisierung der Blöcke ausgeführt werden?
Empirisch, würde ich Nein sagen. Ich habe so etwas wie dieses:
public class Country {
static {
init();
List<Country> countries = DataSource.read(...); //get from a DAO
addCountries(countries);
}
private static Map<String, Country> allCountries = null;
private static void init() {
allCountries = new HashMap<String, Country>();
}
private static void addCountries(List<Country> countries) {
for (Country country : countries) {
if ((country.getISO() != null) && (country.getISO().length() > 0)) {
allCountries.put(country.getISO(), country);
}
}
}
public static Country findByISO(String cc) {
return allCountries.get(cc);
}
}
In den code mit der Klasse, ich glaube so etwas wie:
Country country = Country.findByISO("RO");
Das problem ist, dass ich eine NullPointerException
da die Karte (allCountries
) ist nicht initialisiert. Wenn ich die Haltepunkte in der static
block I können Sie die Karte immer ordnungsgemäß gefüllt, aber es ist, als ob die statische Methode hat keine Kenntnis von der Initialisierung ausgeführt wird.
Kann jemand erklären Sie dieses Verhalten?
Update: ich habe nun mehr Details zu der code. Es ist noch nicht 1:1 (da gibt es mehrere Karten gibt, und mehr Logik), aber ich habe explizit schaute auf die Erklärungen/Referenzen allCountries
und Sie sind, wie oben aufgeführt.
Sehen Sie den vollständigen code für die Initialisierung hier.
Update #2: ich habe versucht, den code vereinfachen, so viel wie möglich und schrieb es sich auf das Fliegen. Der eigentliche code hatte der statischen Deklaration von Variablen nach der Initialisierung. Verursacht ein reset der Referenz, wie Jon wies darauf hin, in der Antwort unten.
Modifizierte ich den code in meinen Beitrag zu reflektieren, so ist es klarer für Leute, die finden die Frage. Tut mir Leid wegen der Verwirrung alle. Ich habe nur versucht, jeder machen das Leben leichter :).
Dank für Eure Antworten!
- können Sie zeigen den code, mit dem Sie initialisieren der Karte ?
- Btw fehlt der Rückgabetyp der findByISO () - Methode in deinem Beispiel.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Bist du falsch.
Aus der JLS Abschnitt 8.7:
Abschnitt 12.4.1 der JLS Staaten:
Ist dies leicht gezeigt werden:
Dein problem ist ein Teil des Codes, dass Sie nicht zeigen, Sie uns. Meine denke ist, dass Sie tatsächlich deklarieren eine lokale variable, wie das ist:
Dass verbirgt die static-variable, verlassen die statische variable null. Wenn dies der Fall ist, ändere es einfach in ein Zuordnung statt einer Erklärung:
EDIT: Ein Punkt erwähnenswert - obwohl Sie habe
init()
als die erste Zeile der statische Initialisierer, wenn Sie eigentlich etwas anderes zu tun, bevor dann (möglicherweise auch in anderen Variablen-Initialisierungen) die Anrufe aus einer anderen Klasse, und diese Klasse ruft zurück in IhreCountry
Klasse, dann wird der code ausgeführt, währendallCountries
ist immer noch null.EDIT: Okay, jetzt können wir sehen, Ihre echten code, ich habe das problem gefunden. Ihre post - code ist dieser:
Aber Ihre real - code ist dieser:
Gibt es zwei wichtige Unterschiede hier:
Die Kombination von denen ist, die Unordnung, die Sie bis: Variablen-Initialisierungen sind nicht alle ausgeführt werden, bevor der statische Initialisierer Initialisierung tritt in textuelle Reihenfolge.
Du bist also der Bestückung der Kollektion... und dann setzen der Referenz auf null.
Abschnitt 12.4.2 der Justiz, Freiheit und Sicherheit garantiert es in Schritt 9 der Initialisierung:
Demonstration-code:
Ausgabe:
Also die Lösung ist entweder, um loszuwerden, die explizite Zuweisung auf null oder verschieben Sie die Deklarationen (und daher Initialisierungen) vor dem statischen Initialisierer, oder (meine Vorliebe) beide.
findByISO
Methode nicht zurück geben. Ich bin immer noch sicher, dass das problem in Ihrem code,... obwohl ich habe eine andere Idee. Wird Bearbeiten.init()
ist eigentlich die erste Linie der Initialisierung und es nicht zu einer beliebigen anderen Klasse, die Verweise auf Land. Es ist nur initialisiert, die mehrere Halterungen im inneren desCountry
Klasse. Sehen Sie den vollständigen code in der hastebin link, den ich geschrieben in meinem edit (am Ende des post).Der statische Initialisierer wird aufgerufen, wenn die Klasse geladen wird, die in der Regel, wenn Sie zuerst 'erwähnt'. Also, Aufruf einer statischen Methode wäre in der Tat auslösen der Initialisierung ist dies das erste mal, dass die Klasse bekommt, auf die verwiesen wird.
Sind Sie sicher, dass die null-Zeiger-Ausnahme aus, die
allcountries.get()
, und nicht aus einer null -Country
zurückgegebenget()
? In anderen Worten, sind Sie sicher, dass die Objekt null ist?Theoretisch, statische block ausgeführt, indem die Zeit classloader lädt die Klasse.
In Ihrem code initialisiert das erste mal, wenn Sie erwähnen die Klasse Land (wahrscheinlich die Zeile oben).
Lief ich dieses:
mit dabei:
und alles richtig geklappt hat. Kannst du die stack-trace des Fehlers?
Ich würde sagen, das problem liegt in der Tatsache, dass der static-block deklariert ist, bevor das eigentliche Feld.
Haben Sie
allCountries = new HashMap();
im statischen Initialisierer block? Der statische Initialisierer block ist eigentlich genannt auf Klasse-Initialisierung.