这些问题来自于一些(通常是编译器生成的)初始化程序代码超过65536字节的字节代码.单个方法不能包含多个要执行的字节码字节(由于
restrictions in the class file format).
像这样的问题的常见来源是这样的大型数组:
byte someBytes = { 1, 2, 3, ..., someBigValue };
这里的问题是这样的字段实际上是在生成的初始化器(构造函数或静态初始化器)中用someBigValue赋值语句初始化的.
枚举值实际上以类似的方式初始化.
给定以下枚举类:
public enum Foo {
CONSTANT(1);
private Foo(int i) {
}
}
我们看看javap -v的输出,看看下面的代码块:
static {};
flags: ACC_STATIC
Code:
stack=5, locals=0, args_size=0
0: new #4 // class Foo
3: dup
4: ldc #7 // String CONSTANT
6: iconst_0
7: iconst_1
8: invokespecial #8 // Method "":(Ljava/lang/String;II)V
11: putstatic #9 // Field CONSTANT:LFoo;
14: iconst_1
15: anewarray #4 // class Foo
18: dup
19: iconst_0
20: getstatic #9 // Field CONSTANT:LFoo;
23: aastore
24: putstatic #1 // Field $VALUES:[LFoo;
27: return
您可以看到有相当多的字节码操作可以使用正确的值处理实例化CONSTANT.如果你有很多这样的枚举值,那么该静态初始化程序块的大小可以容易地超过64k字节的代码,从而使该类不可编译.
可能的解决方法是通过减少参数数量来减少初始化代码的大小(例如,通过根据枚举值的索引计算传递的数量,而不是使用参数).这可能只是给你足够的摇摆空间来进一步扩展.
或者,您可以尝试将枚举分成几个通过实现通用接口连接的枚举.枚举可以按区域/意图/类别/ …分组:
public interface MessageType {
int getId();
}
public enum ConnectionMessage implements MessageType {
INIT_CONNECTION(1),
LOGIN(2),
LOGOUT(3),
CLOSE_CONNECTION(4);
// getId code, constructor, ...
}
public enum FrobnicationMessage implements MessageType {
FROBNICATE_FOO(5),
FROBNICATE_BAR(6),
DEFROB_FOO(7),
DEFROB_BAR(8),
...
// getId code, constructor, ...
}
我假设枚举值实际上是在代码中的某个地方引用的,而不仅仅是纯值持有者,如果它们只保留值,并且单个值在代码中被不同地对待,然后将它们替换为每个数据项实例化的一个类存储在中央资源中可能是最好的方法.