有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java关于常量及其在编译代码中的表示的深入问题

我读了乔希·布洛赫的。我不明白这些短语:使用int枚举的程序很脆弱。因为int enum是常量变量[JLS,4.12.4],它们的int值被编译到使用它们的客户机中。如果更改了与int枚举关联的值,则必须重新编译其客户端。否则,客户端仍将运行,但其行为将不正确。 主要是检查文本。谁能用别的话给我解释一下吗


共 (2) 个答案

  1. # 1 楼答案

    这有两个方面:

    1. 他所写的int enums不是像Java enum那样的“真正的枚举”,而是在int常量中定义/匹配的int值
    • 在Java中,枚举类似于类。在几乎所有方面,您都可以像类一样实现Java枚举,只需一些小限制(私有构造函数,无继承)
    • 您还可以像使用对象变量一样使用Java的枚举变量,使用相同的运算符等
    • 其他语言使用的经典“int enum”通常不会被视为类/对象,而是在Java术语中被视为原语。因此,这使整个“枚举”处理与Java有了很大的不同
    1. 他描述的问题(“如果与int enum关联的值被更改,则必须重新编译其客户端。如果没有,客户端仍将运行,但其行为将不正确。”)仍然适用于与Java枚举有关的某些情况
    • 如果试图存储这些数据,通常(错误地)会将它们的存储值减少为int,即ordinal()值。但是,如果通过在enum类中添加/删除/重新排序enum常量来更改enum的顺序,则它们各自的ordinal()值也将更改。如果然后从数据中恢复枚举,则会加载旧的序数值,但会得到错误的枚举常量。因此,Java枚举中应该始终有一个单独的枚举ID,或者按枚举常量的名称保存和还原这只是Java在更新库时与其他语言可能发生的情况的类比
    • 在Java中,您还可能遇到枚举和更新库的问题。但它不会默默地使用错误的枚举,而是抛出一个运行时错误,并通知您尝试寻址的枚举不再存在
  2. # 2 楼答案

    int和其他原语存储为值,而不是用于正确枚举值的引用。现在,假设您正在使用一个int常量,其值为5somehwere,编译器决定将其内联,即,它用该值替换对该常量的访问

    一个示例假设客户机代码中的以下行:

    static int x = Constants.intEnum; //intEnum has value 5
    

    如果编译器将其内联,字节码基本上类似于:

    static int x = 5; //value is resolved at compile time which is ok because it is constant
    

    现在想象一下你将intEnum更改为7的值。如果不在字节码之上重新编译代码,字节码仍将包含x = 5等价物。只有重新编译客户机才能将其更新为x = 7,并且了解并重新编译库的所有客户机可能不是那么容易,甚至不可取

    另一方面,对正确枚举的访问不会内联,即以下内容仍然相同:

    static MyEnum x = MyEnum.FIVE; //This would be the same as Constants.intEnum
    

    现在,如果您要更改库并将FIVE替换为SEVEN,并且客户端不会被重新编译,您应该会在运行时收到一个异常,告诉您无法找到枚举值FIVE

    此外,如果您的枚举将有一个值和一个getter,例如int getSomeValue(),那么下面的内容也应该保持不变,即不内联(我需要确认这一点,因此如果有人有证据支持或反对这一点,请在commets中分享):

    static int x = MyEnum.THE_VALUE.getSomeValue(); //may return 5 or 7 at runtime
    

    现在对getSomeValue()的调用应该在运行时解决,因此如果从5更改为7,则无需重新编译客户端