Java 如何反序列化 Class 对象,同时保留其与当前加载的 Class 对象的身份?

How can Java deserialize Class objects while preserving their identity to currently loaded Class objects?

如果我序列化一个 Class 对象(例如,HashMap.class),然后在另一个 JVM 实例中反序列化它,事实证明反序列化的 class 与当前加载的那个:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;

final class DeserializationTest {

    static String path = "/home/suseika/test.ser";
    static Class<HashMap> cls = HashMap.class;

    public static void main(String[] args) throws Exception {
        if (args[0].equals("serialize")) {
            serialize();
        } else if (args[0].equals("deserialize")) {
            final Object deserialized = deserialize();

            // The important line, prints "true"
            System.out.println(deserialized == cls); 
        }
    }

    static Object deserialize() throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(path));
        return in.readObject();
    }

    static void serialize() throws Exception {
        FileOutputStream fileOut = new FileOutputStream(path);
        ObjectOutputStream out = new ObjectOutputStream(fileOut);
        out.writeObject(cls);
        out.close();
        fileOut.close();
    }
}

在这种情况下,Java 如何能够反序列化对象以保留身份? Class 似乎没有实现 writeObject()/readObject()/readResolve().

是否可以通过在序列化期间加载特定 class/using 特定 classloader/using 特定 JVM setup/doing 某些内容来打破此行为?是否存在加载的 Class 与反序列化的不同的实例?换句话说,我可以在我的应用程序中依靠这种行为来序列化和反序列化 Class 个对象吗?

How is Java able to deserialize objects in this case so that identity is preserved? Class doesn't seem to implement writeObject()/readObject()/readResolve().

它不需要实现 readObject()writeObject() 来完成这个,但它可以通过实现 readResolve() 或通过 ObjectInputStream 中的特殊逻辑来实现.

How is Java able to deserialize objects in this case so that identity is preserved?

这是因为 class 个实例由 classloader 缓存。

Does Java guarantee that Object.getClass() == Object.getClass()?

Can this behavior be broken with loading a particular class/using a particular classloader/using a particular JVM setup/doing something during serialization?

对于来自不以 java.* 开头的包的 classes 的序列化实例,这可以在 ObjectInputStream 中使用不同的 classloader 来打破(例如 here).

对于 java.* 中的 classes,就像你的情况 (java.lang.Class),只有 Bootstrap class 加载程序可以加载它们,并且鉴于 class 定义在每个 class 加载程序中是唯一的(由 JVM spec 保证)

In other words, can I rely on this behavior in my application to serialize and deserialize Class objects