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)答案相同... –