Java将枚举编译成什么?

8
我和一位同事讨论了Java如何表示枚举。我认为它们像C/C++一样是严格的整数。或者,如果添加行为(类型安全枚举),它会被包装在一个类中。他认为,如果它足够小,Java会将其压缩为一个字节。
然而,我在Oracle网站上找到了这个:
Java编程语言的枚举比其他语言中的枚举更强大,其他语言的枚举只不过是被吹嘘的整数。新的枚举声明定义了一个完整的类(称为枚举类型)。
我理解它们是实际对象。如果是这样,有没有一种方式来优化它们以节省空间?
谢谢!
编辑:正如Jon回答评论中提到的那样,我想知道枚举的序列化大小。

1
如果你需要“优化Java Enums以节省空间”,那么你做错了。具体来说,如果你的Enums占用太多空间,那么很可能是因为你有太多的Enums。 - DwB
我们并不是有太多的枚举类型,而是我们打算在对象之间传递枚举类型。因此,结构越小,发送效率就越高。或者说,这就是我们的想法... - Tony
如果您正在使用枚举来定义类型(例如,这是一个 Blammy 报告,所以它的类型是 enum.Blammy),那么您可能考虑使用多态性代替(比如,类 BlammyReport 继承...)。 - DwB
没错,但是当对象彼此不再有区别时会发生什么呢?所以一个 BlammyReport 和一个 TPSReport 是一样的,但是它们有不同的类型并且需要不同的处理方式。 - Tony
多态胜利!相同的功能可以在父类中实现,但使用类类型来处理差异。 - DwB
我考虑过那样做,但似乎很傻。 - Tony
1个回答

18
不,Java枚举值确实是对象。它们可以具有字段、方法等,并且可以在每个枚举值上有不同的方法实现。但是,它们只有一组固定的值,不像您自己创建枚举类型的实例;有效值集在类型初始化时创建。除非您拥有大量枚举值,否则您甚至不需要考虑优化。
请注意,易于实现的一个优化是,在逻辑上考虑枚举值集时始终使用EnumSet。这使用位模式来高效地表示集合。
(请注意,这里的C#更接近于C++而不是Java - C#的枚举可悲地没有面向对象。叹气。)
编辑:根据文档,枚举值按名称序列化:
引用: 支持添加对枚举类型的序列化处理,该处理是在5.0版中新增的。序列化枚举实例的规则与序列化“普通”可序列化对象的规则不同:枚举实例的序列化形式仅包含其枚举常量名称以及标识其基本枚举类型的信息。反序列化行为也不同--类信息用于查找适当的枚举类,并使用该类和接收到的常量名称调用Enum.valueOf方法以获取要返回的枚举常量。
如果你真的需要一个小的序列化表单,那么你应该避开Java内置的序列化,因为它相对冗长(而且非常敏感版本问题)。有各种各样的替代方案 - 我最了解的是Protocol Buffers,它将枚举值序列化为整数。

EnumSet非常不错,但处理的是不同的问题。我们关心的空间问题更多地与序列化尽可能小的对象有关。然而,如果我们将枚举剥离到最基本的状态,这似乎是一个无意义的观点。 - Tony
@Tony:你应该提到你追求“序列化”大小——我怀疑枚举值被序列化为它们的序数值。 - Jon Skeet
@Jon 更新了问题。当我阅读您的答案时,我意识到我应该澄清一下。谢谢。 - Tony
@Jon 如果证明它们可以序列化为顺序大小,那将是决定性的。 - Tony
1
@Tony:我更新了我的答案。事实证明,序列化是按名称而不是按顺序值进行的(请参阅引用文档)-但如果您正在使用Java的二进制序列化,并且大小是一个重要考虑因素,您应该考虑其他替代方案。 - Jon Skeet
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接