【问题标题】:why default serialization is prevented in enum class [duplicate]为什么在枚举类中阻止默认序列化[重复]
【发布时间】:2016-01-04 10:42:55
【问题描述】:

我一直在网上搜索一些与java中的枚举类相关的查询的答案。

我的问题是为什么在枚举类中阻止了默认的反序列化。我可以看到枚举类实现了 Serializable 接口,但它也有如下 2 个方法 --

 private void readObject(ObjectInputStream in) throws IOException,
    ClassNotFoundException {
    throw new InvalidObjectException("can't deserialize enum");
}

private void readObjectNoData() throws ObjectStreamException {
    throw new InvalidObjectException("can't deserialize enum");
}

看了这堂课,我更困惑了。任何帮助将不胜感激。提前致谢。

我更加困惑,因为 ENUM 本身实现了可序列化接口并且也有上述方法抛出“throw new InvalidObjectException("can't deserialize enum");”例外。所以我对以上两种方法的用途没有清楚的了解?

上面两个方法上的cmets也说“防止默认反序列化”是什么意思?

【问题讨论】:

  • 不是重复请检查编辑。

标签: java serialization enums


【解决方案1】:

枚举值是可序列化的——这就是实现Serializable 接口所要求的全部。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Dummy {

    public enum Color {
        RED, GREEN, BLUE
    }

    public static void main(String[] args) throws Exception {

        System.out.println(deserialize(serialize(Color.GREEN), Color.class));
    }

    private static <T> T deserialize(byte[] data, Class<T> cls) throws IOException, ClassNotFoundException {

        try (final ByteArrayInputStream stream = new ByteArrayInputStream(data);
             final ObjectInputStream reader = new ObjectInputStream(stream)) {

            return cls.cast(reader.readObject());
        }
    }

    private static byte[] serialize(Serializable obj) throws IOException {

        final ByteArrayOutputStream stream = new ByteArrayOutputStream();

        try {

            try (final ObjectOutputStream writer = new ObjectOutputStream(stream)) {

                writer.writeObject(obj);
            }

        } finally {

            stream.close();
        }

        return stream.toByteArray();
    }
}

但是,由于枚举常量的特殊性质,运行时不能使用默认的序列化机制,因为这将允许构造给定常量的多个值,违反了枚举常量是单例的保证。

因此,运行时使用“非默认”机制来序列化/反序列化枚举常量,从而确保单例属性。通过覆盖readObject 解除默认机制只是一种安全措施,它确保您不能通过反序列化恶意破解的字节流来欺骗虚拟机创建新常量。

TL;DR 枚举常量完全可以(反)序列化,正如基类Enum 实现Serializable 接口所声称的那样。但是,在内部,VM/运行时专门处理序列化,并禁用这些对象的默认机制。

【讨论】:

    【解决方案2】:

    很简单,因为在 Java 中 enum 在 JVM 中是单例的,deserialize() 会创建另一个实例,从而破坏单例合约。

    【讨论】:

    • 表示可以序列化 Enum 但不能反序列化?
    • 由于deserialize()被阻止,您不能使用默认方式传输enum对象,即序列化enum对象,希望它们可以在另一个JVM中正确反序列化。一种常见的方法是使用cardinal() 值。
    猜你喜欢
    • 1970-01-01
    • 2020-08-08
    • 2023-03-20
    • 2016-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-23
    • 1970-01-01
    相关资源
    最近更新 更多