6

Mam klasy gospodarstwa dużą wierzchowca generowanych stałych jako takie:Jak obejść limit rozmiaru statycznym initialiser w Javie przy inicjalizacji duże ilości stałych

public class Constants extends SomeBaseClass { 

    // init() is defined in some base class... 
    public static final XXX KEY1 = init(...); 
    public static final XXX KEY2 = init(...); 
    public static final XXX KEY3 = init(...); 

    // ... 
    public static final XXX KEY2000 = init(...); 
} 

Gdy liczba generowanych stałych jest bardzo wysoka, powoduje to statyczny inicjator, który jest większy niż górny limit dla metod Java (tj.> 64kb), powodując błąd kompilatora. Jednym rozwiązaniem jest utworzenie kilku „metody inicjalizacji bloków” dla bloków, które może być zagwarantowane, aby wytworzyć mniej niż 64kb bajtu kodu, tak, że pasują do metody:

public class Constants extends SomeBaseClass { 

    public static XXX KEY1; 
    public static XXX KEY2; 
    public static XXX KEY3; 

    // ... 
    public static XXX KEY2000; 

    static { 
    initialise0001To1000(); 
    initialise1001To2000(); 
    } 

    private static void initialise0001To1000() { 
    KEY1 = init(...); 
    KEY2 = init(...); 
    KEY3 = init(...); 
    // ... 
    } 

    private static void initialise1001To2000() { 
    // ... 
    KEY2000 = init(...); 
    } 
} 

Wadą jest to, że mogę nie deklarujemy już stałych jako final, ponieważ nie są one już inicjalizowane bezpośrednio w statycznym inicjatorze.

Moje pytanie brzmi: jak mogę ominąć to ograniczenie kompilatora/maszyny JVM w sposób, w jaki nadal mogę generować stałe static final?

+0

Jak skończyć z systemem do tego problemu? Czy ten kod jest automatycznie generowany z innego pliku? – templatetypedef

+0

@templatetypedef: To jest prawdziwy błąd w generatorze kodu źródłowego [jOOQ] (http://www.jooq.org). Generuje klucze podstawowe, klucze unikalne i klucze obce jako stałe obiekty z bazy danych. Wygląda na to, że 2000 kluczy to zbyt wiele dla jOOQ do obsłużenia: https://groups.google.com/d/topic/jooq-user/2g96fI1Yrj8/discussion –

+0

Czy możesz użyć do tego celu "atrapowych" warstw dziedziczenia? Posiadaj klasę podstawową z pewną nazwą niepubliczną, która zawiera 1000 stałych i ma ustawiony statyczny inicjator. Następnie klasa pochodna, która dodaje 1000 więcej, klasa z subdomenami, która dodaje kolejne 1000 itd.? Tylko klasa pochodna byłaby kiedykolwiek używana do jakichkolwiek celów, z wyjątkiem wyprowadzania innych klas w zespole. – supercat

Odpowiedz

1

W końcu zdecydowałem się na rozwiązanie obejmujące klasy zagnieżdżone. To zostało zasugerowane w komentarzu do this answer here przez użytkownika Loadmaster.Klasy zagnieżdżone mają dwie zalety:

  • Pozwalają na ukrywanie te szczegóły implementacji obejście od świata zewnętrznego poprzez bycie private klas zagnieżdżonych
  • Pozwalają one na utrzymywanie stałych final

Ale mają też wadę w porównaniu do templatetypedef's rozwiązania:

  • będę napotkasz ten sam problem znowu z dużo lar numery ger stałych

Teraz jednak wydaje się być najbardziej odpowiednie rozwiązanie:

public class Constants { 

    public static XXX KEY1 = Constants1.KEY1; 
    public static XXX KEY2 = Constants1.KEY2; 
    public static XXX KEY3 = Constants1.KEY3; 

    // ... 
    public static XXX KEY2000 = Constants2.KEY2000; 

    // Nested class holding 1000 constants 
    private static class Constants1 extends SomeBaseClass { 
    KEY1 = init(...); 
    KEY2 = init(...); 
    KEY3 = init(...); 
    // ... 
    } 

    // Nested class holding the next 1000 constants 
    private static class Constants2 extends SomeBaseClass { 
    // ... 
    KEY2000 = init(...); 
    } 

    // Keep generating nested classes for more constants... 
    private static class Constants3 ... {} 
} 
7

Jedną z możliwości byłoby użycie dziedziczenia - posiada szereg zajęć Constants1, Constants2, ..., ConstantsN że wszystko definiować stałe, wtedy każdy jeden dziedziczą z poprzedniej. Ostateczna klasa Constants może następnie bezpośrednio dziedziczyć z ostatniego z nich. Pozwala to również oznaczyć wszystko jako final.

Z ciekawości, w jaki sposób powstał plik tak duży, że nie można dopasować kodu inicjalizacyjnego do limitu 64 KB?

Mam nadzieję, że to pomoże!

+0

Hmm, tak, byłby to poprawny sposób obejścia, miłe myślenie. Mogłabym również umieścić wszystkie stałe w interfejsach i pozwolić, aby 'Constants' zaimplementował je wszystkie ... –

+0

O twoim dodanym pytaniu, odpowiedź znajduje się w komentarzach ... –

+1

Możesz to zrobić również z klasami zagnieżdżonymi, co pozwoli ci umieścić wszystko w jednym pliku źródłowym. –

0

Czy to nie działa? NIE. Zobacz komentarze, dlaczego taka odpowiedź nie rozwiąże problemu.

To pozwoli na zachowanie zmiennych statycznych i ułatwi automatyczne generowanie. Jednak java zwija wszystkie statyczne bloki init w jeden gigantyczny statyczny blok init, przez co problem nie został rozwiązany.

public class Constants extends SomeBaseClass { 

    // init() is defined in some base class... 
    public static final XXX KEY1 ; 
    static 
    { 
     KEY1 = init(...); 
    } 
    public static final XXX KEY2 ; 
    static 
    { 
     KEY2 = init(...); 
    } 
    public static final XXX KEY3 ; 
    static 
    { 
     KEY3 = init(...); 
    } 

    // ... 

} 
+0

Ta odpowiedź już istniała (w międzyczasie została usunięta). Wygląda na to, że klasa kodu bajtowego ma tylko jeden statyczny inicjator. Kompilator łączy wszystkie instrukcje inicjalizacji z jednym, myślę, że –

+0

To wstyd. Czy to samo by się stało, gdybyś użył enum? Wady XXX musi być tą samą klasą i musiałbyś przerobić kod, aby init() był wywołaniem do konstruktora wyliczeniowego. – emory

+0

Nie mogę użyć wyliczenia. Typ "XXX" w realnym świecie ma parametry typu ogólnego ...: -/Ale wyobrażam sobie, że pod maską, enumy dzielą tę samą statyczną logikę inicjalizacyjną z regularnymi klasami ... –

-1

Możesz mieć tyle bloków inicjalizacji statycznej, ile chcesz.

+0

To jest tak samo jak odpowiedź [emory] (http://stackoverflow.com/a/10842759/521799) ... –

Powiązane problemy