Mohu zaručit pořadí, ve kterém jsou statické inicializátory běží v Javě?

hlasů
5

Mám třídu Set (To je J2ME, takže jsem omezený přístup ke standardní rozhraní API, jen proto, aby vysvětlil svou zdánlivou kolu znovuobjevení). Já používám svůj set třídu k vytvoření stálé sady věcí ve skupin a podskupin. Tak nějak vypadá takto ...

class ParentClass
{
    protected final static Set THE_SET = new Set() {{
        add(one);
        add(two);
        add(three);
    }};
}


class SubClass extends ParentClass
{
    protected final static Set THE_SET = new Set() {{
        add(four);
        add(five);
        add(six);
        union(ParentClass.THE_SET); /* [1] */
    }};
}

Vše vypadá v pořádku, s výjimkou řádku v [1] způsobí výjimky prázdného ukazatele. Pravděpodobně to znamená, že statické initialiser v podtřídě je spuštěn dříve, než to nadřazené třídy. To mě překvapilo, protože jsem si myslel, že by spuštění statické bloky v jakýchkoliv nových dovozu první, před spuštěním kteréhokoli v instatiated podtřídy.

Mám pravdu v tomto předpokladu? Existuje nějaký způsob, jak ovládat nebo pracovat tento problém vyřešit?

Aktualizace:

Věci jsou ještě podivnější. Zkoušel jsem to místo (Poznámka: ‚nový ParentClass ()‘ řádek):

class ParentClass
{
    public ParentClass()
    {
        System.out.println(THE_SET);
    }

    protected final static Set THE_SET = new Set() {{
        add(one);
        add(two);
        add(three);
    }};
}


class SubClass extends ParentClass
{
    protected final static Set THE_SET = new Set() {{
        System.out.println(a);
        new ParentClass();
        System.out.println(b);
        add(four);
        System.out.println(c);
        add(five);
        System.out.println(d);
        add(six);
        System.out.println(e);
        union(ParentClass.THE_SET); /* [1] */
        System.out.println(f);
    }};
}

A výstup je divné:

a
[one, two, three]
b
c
d
e
Exception in thread main java.lang.ExceptionInInitializerError
Caused by: java.lang.NullPointerException

Takže ParentClass se inicializuje, ale podtřídy nemá přístup k němu v jeho statické inicializátor.

Položena 27/04/2009 v 14:10
zdroj uživatelem
V jiných jazycích...                            


6 odpovědí

hlasů
3

Neexistuje žádná záruka pro statické inicializátor pořadí mezi třídami. V rámci třídy, běhají v pořadí zdrojového kódu.

Pokud si myslíte o tom, therre opravdu nemůže být objednávka mezi třídami, protože nemáte kontrolu, pokud jsou třídy naložena buď; můžete dynamicky načíst třídu nebo JVM mohl optimalizovat pořadí načítání.

Odpovězeno 27/04/2009 v 14:11
zdroj uživatelem

hlasů
2

Dokonce i když jste neměli mít extends ParentClasstam, používání ParentClassby mělo způsobit, aby se stal inicializována.

Kde se věci stanou ošidné je, když máte cykly. S cyklem je možné přistupovat třídu před tím, než byl plně inicializován. Jako Java je vícevláknových systém, můžete mít také problémy s zablokování a ras.

Může být vaše implementace Java ME je buggy (není neslýchané). Části vaše úplné ParentClassodkazy vaší ChildClass. Nebo snad existuje nějaký jiný application / library bug.

Na příbuznou notu, pokud ne -target 1.4, nebo později, vnější tento vnitřní třídy se inicializuje, jakmile by se dalo očekávat. Jak je uvedeno váš kód používá (technicky) vnitřní třídy ve statickém kontextu, takže by neměl být problém.

Také je zajímavé poukázat na to, že statická inicializace je trochu zmatený v situacích, jako je tato, protože jste skutečně čtyři třídy tam.

Odpovězeno 27/04/2009 v 14:31
zdroj uživatelem

hlasů
7

Je to to, co se snažíte dosáhnout? Nebo potřebujete lokální implementaci rozhraní Set?

class ParentClass
{
    protected final static Set THE_SET;

    static {
        THE_SET = new HashSet();
        THE_SET.add("one");
        THE_SET.add("two");
        THE_SET.add("three");
    }
}


class SubClass extends ParentClass
{
    protected final static Set THE_SECOND_SET;

    static {
        THE_SECOND_SET = new HashSet();
        THE_SECOND_SET.add("four");
        THE_SECOND_SET.add("five");
        THE_SECOND_SET.add("six");
        union(ParentClass.THE_SET); /* [1] */
    }
}
Odpovězeno 27/04/2009 v 14:32
zdroj uživatelem

hlasů
0

Vzhledem k tomu, linkového výstupu [ „one“, „dva“, „tři“], je v podstatě nemožné, aby ParentClass.THE_SET nikdy nebyl inicializován.

Samozřejmě, že je možné, že tam není jen jeden ClassLoader účastní, ale to by bylo jistě užitečné vidět metody a číslo řádku, kde je nulový ukazatel stane.

Odpovězeno 27/04/2009 v 14:36
zdroj uživatelem

hlasů
2

Stačí přestat zneužívat koncepci anonymních tříd pro inicializaci instance (takzvaný „dvojité rovnátka idiom“).

Odpovězeno 27/04/2009 v 14:57
zdroj uživatelem

hlasů
-1

Myslím, že něco podobného byl napsán v Javě puzzle knize nebo Google je YouTube video o java triků.

Odpovězeno 27/04/2009 v 19:36
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more