6

我有一個類持有生成常數的大的安裝這樣:初始化大量的常量時,如何規避Java中的靜態初始化器的大小限制

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(...); 
} 

時產生的常數的數目是非常高,這會導致靜態初始化程序大於Java方法大小(即> 64kb)的上限,從而導致編譯器錯誤。一種解決方案是創建該可保證比的字節碼64KB產生較少的塊,以使得它們適合的方法的幾個「塊初始化方法」:

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(...); 
    } 
} 

這樣做的缺點是,我可以不再聲明常量爲final,因爲它們現在不再直接在靜態初始化程序中初始化。

我的問題是,我怎樣才能規避編譯器/ JVM限制的方式,我仍然可以生成static final常量?

+0

你怎麼會運行到這個問題?這段代碼是從另一個文件自動生成的嗎? – templatetypedef

+0

@templatetypedef:這是[jOOQ](http://www.jooq.org)的源代碼生成器中的一個實際錯誤。它從數據庫生成主鍵,唯一鍵和外鍵作爲常量對象。看起來2000個鍵對於jOOQ來說太多了:https://groups.google.com/d/topic/jooq-user/2g96fI1Yrj8/discussion –

+0

你可以使用「虛擬」繼承層來做到這一點嗎?有一個基類,其中包含一些非公用名稱,其中包含1,000個常量,並有一個靜態初始化程序設置它們。那麼派生類又增加了1000個,派生類又增加了1000個,等等?除衍生程序集中的其他類以外,只有最派生的類纔會用於任何目的。 – supercat

回答

1

我終於找到了一個涉及嵌套類的解決方案。這在用戶Loadmasterthis answer here的評論中被建議。嵌套類有兩個優點:

  • 它們允許通過被private嵌套類
  • 它們允許保持常量final

但他們也有一個缺點隱藏從外面的世界,這些解決辦法的實施細則相對於templatetypedef's解決方案:

  • 我會遇到同樣的問題,常量

眼下的蒙古包數字,然而,這似乎是最合適的解決方案:

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

一個選擇是使用繼承 - 有一系列的類Constants1,Constants2,...,ConstantsN所有定義常量,然後讓每個類都繼承前一個。最後的類Constants可以直接從最後一個類繼承。這也讓你標記一切final

出於好奇,你是如何得到一個非常大的文件,以至於無法將初始化代碼放入64KB的限制?

希望這會有所幫助!

+0

嗯,是的,這將是一個有效的解決方法,好想法。我也可以將所有常量放置在接口中,並讓'Constants'實現所有這些... –

+0

關於您添加的問題,回覆在評論中... –

+1

您也許可以使用嵌套類來完成此操作,這將允許您將所有內容放入單個源文件中。 –

0

這不工作? NO。請參閱評論爲什麼這種答案不會解決問題。

它可以讓你保持最終的靜態變量,它會更容易自動生成。 但是java將所有的靜態初始化塊合併爲一個巨大的靜態初始化塊,因此問題沒有解決。

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

已經有類似的答案(同時刪除)。似乎一個字節碼類只有一個靜態初始化器。編譯器將所有初始化語句合併到一個單獨的語句中,我認爲 –

+0

這是一個恥辱。如果你使用枚舉,會發生同樣的事情嗎?缺點XXX必須是相同的類,您將不得不重新編寫代碼,以便init()是對枚舉構造函數的調用。 – emory

+0

我無法使用枚舉。真正的世界類型'XXX'具有泛型類型參數...: - /但我想象在引擎蓋下,枚舉與常規類共享相同的靜態初始化邏輯... –

-1

您可以根據需要擁有儘可能多的靜態初始化塊。

+0

這與[emory's](http://stackoverflow.com/a/10842759/521799)答案相同... –