Java中的最大枚举元素数

Rne*_*net 28 java enums switch-statement

Java中枚举允许的最大元素数是多少?

我想找出switch语句中的最大个案数.由于switch中允许的最大基本类型是int,因此我们有-2,147,483,648到2,147,483,647的情况和一个默认情况.但是也允许枚举...所以问题..

Thi*_*ilo 33

类文件格式规范:

ClassFile结构的16位constant_pool_count字段(第4.1节)将每类或每接口常量池限制为65535个条目.这是对单个类或接口的总复杂性的内部限制.

我相信这意味着你不能在单个类中拥有超过65535个命名的"东西",这也会限制枚举常量的数量.

如果看到一个有20亿个案例的交换机,我可能会杀死触及该代码的任何人.

幸运的是,这不可能发生:

每个非本机非抽象方法的代码量由Code属性(第4.7.3节)的exception_table中的索引大小限制为65536字节,在LineNumberTable属性(第4.7.8节)中,在LocalVariableTable属性中(§4.7.9).

  • 不幸的是,这个答案似乎是不正确的.虽然逻辑看似合理,但实际上并不是那样.在Java 7和8中,单个java文件中的Enum常量限制为2746.任何大于2746的内容都将导致"错误:代码太大" (8认同)
  • LineNumberTable不是阻塞程序 - 可以在一行中编写完整的交换机/ 20亿个案例块;) (6认同)
  • @Andreas_D:它仍然说"每个方法65536字节(字节代码)".源格式化不应该有任何影响. (6认同)
  • (我的评论只不过是一个笑话) (3认同)

Der*_*rek 12

枚举元素的最大数量是2746.阅读规范是非常误导的,并导致我创建一个有缺陷的设计,假设我永远不会达到64K甚至32K高水位.不幸的是,这个数字远低于规格似乎表明的数字.作为测试,我尝试了以下Java 7和Java 8:将以下代码重定向到一个文件,然后编译生成的.java文件.

    System.out.println("public enum EnumSizeTest {");
    int max = 2746;
    for ( int i=0; i<max; i++) {
        System.out.println("VAR"+i+",");
    }
    System.out.println("VAR"+max+"}");
Run Code Online (Sandbox Code Playgroud)

结果,2746个工作,2747没有.

在2746个条目之后,编译器会抛出一个代码太大的错误,比如

EnumSizeTest.java:2:错误:代码太大了

反编译此Enum类文件时,限制似乎是由为静态构造函数(主要)中的每个枚举值生成的代码引起的.


Dea*_*ler 7

好吧,在jdk1.6上我达到了这个极限.有人在xsd中有10,000枚枚举,当我们生成时,我们得到一个60,000行枚举文件,我得到了一个很好的java编译错误

[错误]无法执行目标org.apache.maven.plugins:maven-compiler-plugin:2.0.2:项目框架上的编译(default-compile):编译失败[ERROR]/Users/dhiller/Space/ifp-core /framework/target/generated-sources/com/framework/util/LanguageCodeSimpleType.java:[7627,4]代码太大

所以很可能这个限制比这里的其他答案要低得多,或者可能产生的评论等产生了太大的空间.注意java编译器错误中的行号是7627,但是如果行限制是7627,我想知道行长度限制是什么;)这可能是类似的.即.限制可能不是基于枚举的数量,而是基于行长度限制或文件限制中的行数,因此您可以将枚举重命名为A,B等非常小,以使更多枚举符合枚举.

我不敢相信有人写了一个带有10,000枚枚举的xsd ......他们必须生成xsd的这一部分.


Tho*_*s W 7

枚举肯定有限制,主要(硬)限制大约32K值.它们受Java类最大值的限制,包括"常量池"(64K条目)和 - 在某些编译器版本中 - 对静态初始化程序的方法大小限制(64K字节码).

内部'枚举'初始化,每个值使用两个常量 - FieldRef和Utf8字符串.这给出了~32K值的"硬限制".

较旧的编译器(至少Eclipse Indigo)也遇到了静态初始化器方法大小的问题.使用24字节的字节码来实例化每个值并将其添加到values数组中.可能遇到约2730个值的限制.

新的编译器(JDK 7至少)自动分割大静态初始化关闭到名为方法" enum constant initialization$2"," enum constant initialization$3"等等,以便不受到所述第二极限.

您可以通过反汇编字节码javap -v -c YourEnum.class来查看其工作原理.

[理论上可以将"旧式"Enum类编写为手动编码的Java,以打破32K限制并接近64K值.方法是通过反射初始化枚举值,以避免在池中需要字符串常量.我测试了这种方法,它在Java 7中运行,但是这种方法(安全问题)的可取性值得怀疑.

编者注:Utf8是Java类文件IIRC中的内部类型,它不是一个错误的纠正.


Zhe*_*lov 7

Java 15+ 更新

在 JDK 15 中,枚举中常量的最大数量提高到约 4103:https://bugs.openjdk.java.net/browse/JDK-8241798

这是通过将静态初始化器分为两部分来实现的:

Java 15 之前(伪代码):

enum E extends Enum<E> {
    ...

    static {
        C1 = new E(...);
        C2 = new E(...);
        ...
        CN = new E(...);
        $VALUES = new E[N];
        $VALUES[0] = C1;
        $VALUES[1] = C2;
        ...
        $VALUES[N-1] = CN;
    }
}
Run Code Online (Sandbox Code Playgroud)

从 Java 15 开始:

enum E extends Enum<E> {
    ...

    static {
        C1 = new E(...);
        C2 = new E(...);
        ...
        CN = new E(...);
        $VALUES = $values();
    }

    private static E[] $values() {
        E[] array = new E[N];
        array[0] = C1;
        array[1] = C2;
        ...
        array[N-1] = CN;
        return array ;
    }
}
Run Code Online (Sandbox Code Playgroud)

这允许静态初始化程序包含更多代码(直到达到 64 KB 限制),从而初始化更多枚举常量。