为什么枚举单例是序列化安全的



内部如何在Enum中进行序列化/反序列化?jvm如何在(序列化)之前和(反序列化)之后生成相同的哈希码?

序列化特别对待enum。基本上,它只存储对其class的引用和常量的名称。反序列化时,该信息用于查找现有的enum类型的运行时对象。

因此,如果您在同一运行时中反序列化enum常量,您将获得您已序列化的相同运行时实例。

但是,在另一个JVM中反序列化时,哈希码可能不同。但是拥有相同的哈希码并不是单例的必要条件。重要的一点是永远不要有该类的另一个实例,这是可以保证的,因为序列化实现永远不会创建enum类型的实例,而只会查找现有的常量。

在Enum内部序列化/反序列化是如何发生的?

在Java中不能序列化枚举。只能序列化对Enum的引用。这意味着如果你的枚举有任何私有字段,它们将不会被写入或恢复。

jvm如何在(序列化)之前和(反序列化)之后生成相同的hashcode ?

JVM如何生成hashCode并没有在JLS中指定,实际上在源代码中有多个实现。但是,Oracle 8 update 45 JVM在重启后会以相同的顺序生成相同的hashCodes。

Object[] objs = new Object[5];
for(int i=0;i<objs.length;i++) {
    objs[i] = new Object();
}
RetentionPolicy[] values = RetentionPolicy.values();
System.out.println(objs+": "+objs.hashCode());
for (Object obj : objs) {
    System.out.println(obj+": "+obj.hashCode());
}
for (RetentionPolicy policy : values) {
    System.out.println(policy+": "+policy.hashCode());
}

如果你用new Object[5]运行它,它打印

[Ljava.lang.Object;@677327b6: 1735600054
java.lang.Object@14ae5a5: 21685669
java.lang.Object@7f31245a: 2133927002
java.lang.Object@6d6f6e28: 1836019240
java.lang.Object@135fbaa4: 325040804
java.lang.Object@45ee12a7: 1173230247
SOURCE: 856419764
CLASS: 621009875
RUNTIME: 1265094477

如果我将数组大小减小到2,它将打印

[Ljava.lang.Object;@677327b6: 1735600054
java.lang.Object@14ae5a5: 21685669
java.lang.Object@7f31245a: 2133927002
SOURCE: 1836019240
CLASS: 325040804
RUNTIME: 1173230247

注意它是如何以相同的顺序生成相同的hashCodes的。如果我完全注释掉Object[]代码。

SOURCE: 1735600054
CLASS: 21685669
RUNTIME: 2133927002

每次运行程序都看到相同的hashCodes的原因是它在检查枚举的hashCodes之前创建了相同数量的hashCodes。

注意:一个对象没有一个系统hashCode,直到你要求它来减少创建对象的成本。

我写了一个简单的enum类。例:

public enum EnumTest{
    
    IND(1),
    ORG(2);
    
    int deger;
    
    EnumTest(int deger){
        this.deger = deger;
    }
    
}

在我们编译了这个枚举类之后,我们可以使用javap工具使用javap EnumTest命令。

  public final class EnumTest extends java.lang.Enum{
    public static final EnumTest IND;
    public static final EnumTest ORG;
    int deger;
    public static EnumTest[] values();
    public static EnumTest valueOf(java.lang.String);
    static {};
}

可以看到上面javap工具生成的文本,枚举实例是静态的,静态变量不能序列化。

相关内容

最新更新