你可以在java枚举中拥有的成员数量限制是多少?

时间:2009-12-01 00:40:06

标签: java performance compiler-construction enums runtime

假设你在java中有一个假设的枚举(纯粹出于演示目的,这不是我非常期待使用的代码):

enum Example{
    FIRST,
    SECOND,
    THIRD,
    ...
    LAST;
}

在编译器停止之前,你可以在枚举中拥有的最大成员数是多少?

其次,当您的代码引用枚举时,运行时是否有任何性能差异,例如10个成员而不是100或1,000(除了存储大型类所需的明显内存开销)?

4 个答案:

答案 0 :(得分:13)

语言规范本身没有限制。然而,classfile有许多限制枚举数量的限制,上限为aruond 65,536(2 ^ 16)枚举:

字段数 JVMS 4.1指定ClassFile最多可包含65,536(2 ^ 16)个字段。枚举作为静态字段存储在类文件中,因此枚举值和枚举成员字段的最大数量为65,536。

常量池 JVMS还指定常量池最多可达65,536。常量池存储所有字符串文字,类型文字,超类型,超级接口类型,方法签名,方法名称, AND 枚举值名称。因此,必须少于2 ^ 16个枚举值,因为名称字符串需要共享该常量池限制。

静态方法初始化 方法的最大限制为65,535字节(以字节码为单位)。因此Enum的静态初始化程序必须小于64Kb。虽然编译器可能会将其拆分为不同的方法(查看Bug ID: 4262078)以将初始化分发为小块,但编译器当前不会这样做。

长话短说,没有简单的答案,答案不仅取决于枚举值的数量,还取决于枚举的方法,接口和字段的数量!

答案 1 :(得分:10)

找出这类问题答案的最佳方法是尝试一下。从一个小的Python脚本开始生成Java文件:

n = input()
print "class A{public static void main(String[] a){}enum B{"
print ','.join("C%d" % x for x in range(n))
print '}}'

现在试试1,10,100,1000 ......工作正常,然后是BAM:

A.java:2:代码太大了 C0,C1,C2,C3,C4,C5,C6,C7,C8,C9,C10,C11,C12,C13,C14,C15,C16,C17,C18,C19,C20,C21,C22,... < / p>

好像我达到某种内部限制。不确定它是否是文档限制,如果它取决于我的编译器的特定版本,或者它是否依赖于系统限制。但对我来说,限制大约是3000,并且似乎与源代码大小有关。也许你可以编写自己的编译器来绕过这个限制。

答案 2 :(得分:-2)

这是对原始问题的评论的扩展。

有大量枚举存在多个问题。

主要原因是,当您拥有大量数据时,它往往会发生变化,或者如果不是,您通常会想要添加新项目。这样的豁免就像永远不会改变的单位转换一样,但是大多数情况下你想要从文件中读取这样的数据到一个类的集合而不是枚举。

添加新项目是有问题的,因为它是一个枚举,你需要物理修改你的代码,除非你总是使用枚举作为集合,如果你总是使用它们作为集合,为什么要让它们成为枚举?

你的数据没有变化的情况 - 比如转换单位,你要转换英尺,英寸等。你可以做这个作为枚举,那里会有很多,但是把它们编码为枚举你失去了数据驱动程序的能力。例如,用户可以从您的“单位”填充的下拉列表中进行选择,但同样,这不是“ENUM”用法,而是将其用作集合。

另一个问题是重复你的枚举引用。你几乎肯定会有一些非常重复的东西,如:

if(userSelectedCard() == cards.HEARTS)
    graphic=loadFile("Heart.jpg");
if(userSelectedCard() == cards.SPADES)
    graphic=loadFile("Spade.jpg");

哪个是错的(如果你可以眯着眼睛看不到字母,在你的代码中看到这种模式,你知道你做错了)。

如果卡片存放在卡片收藏中,则使用起来会更容易:

graphic=cards.getGraphicFor(userSelectedCard());

我并不是说这也不能用enum来完成,但是我说我看不出你如何使用这些作为枚举而没有像我发布的那样令人讨厌的代码块上方。

我也不是说没有枚举的案例 - 它们很多,但是当你得到的不多时(7个是一个很好的数字),你可能会更好的与其他一些结构

我想这个例外是当你对具有那么多类型的现实世界的东西进行建模时,每个东西必须用不同的代码来解决,但即便如此,你最好还是使用数据文件将名称绑定到某些代码来运行并将它们存储在哈希中,以便您可以使用以下代码调用它们:hash.get(nameString).executeCode()。这样,你的“nameString”再次是数据而不是硬编码,允许在别处进行重构。

如果您习惯于像这样粗暴地对代码进行分解,那么您可以将许多程序的大小减少50%或更多。

答案 3 :(得分:-3)

如果你不得不问,你可能做错了什么。实际限制可能相当高,但我认为,一个超过10左右的值的枚举将是非常可疑的。将其分解为相关集合或类型层次结构或其他内容。