Ответ 1
Эти проблемы возникают из-за того, что некоторый (часто генерируемый компилятором) код инициализатора превышает 65536 байт байтового кода. Один метод не может содержать больше, чем должно быть выполнено много байтов байтового кода (из-за ограничений в формате файла классов).
Общим источником таких проблем являются такие большие массивы, как:
byte someBytes = { 1, 2, 3, ..., someBigValue };
Проблема в том, что такие поля фактически инициализируются операторами присваивания someBigValue в сгенерированном инициализаторе (конструктор или статический инициализатор).
Значения Enum фактически инициализируются аналогичным образом.
С учетом следующего класса перечисления:
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 "<init>":(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 байт кода и, таким образом, сделать класс несовместимым.
Возможным обходным решением является уменьшение размера инициализирующего кода за счет уменьшения количества аргументов (например, путем вычисления числа, прошедшего в соответствии с индексом значения перечисления вместо использования аргумента). Это может просто дать вам достаточно места для маневра, чтобы расширить это немного дальше.
В качестве альтернативы вы можете попробовать расщепить свой enum на несколько перечислений, связанных посредством реализации общего интерфейса. Перечисления могут быть сгруппированы по области/намерению/категории/...:
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, ...
}
Я предполагаю, что значения перечисления на самом деле упоминаются где-то в вашем коде, а не только в чистых держателях значений, если они содержат только значения, а отдельные значения не обрабатываются по-разному в вашем коде, а затем заменяют их одним экземпляром, на элемент данных, хранящийся в центральном ресурсе, вероятно, лучший подход.