【问题标题】:How can Java deserialize Class objects while preserving their identity to currently loaded Class objects?Java 如何反序列化 Class 对象,同时保留当前加载的 Class 对象的身份?
【发布时间】:2016-06-23 20:04:06
【问题描述】:

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

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()

是否可以通过加载特定类/使用特定类加载器/使用特定 JVM 设置/在序列化期间执行某些操作来打破这种行为?是否存在加载的Class 与反序列化的不同的情况?换句话说,我可以依靠我的应用程序中的这种行为来序列化和反序列化Class 对象吗?

【问题讨论】:

标签: java serialization classloader


【解决方案1】:

在这种情况下,Java 如何能够反序列化对象以保留身份?

这是因为类实例被类加载器缓存。

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

是否可以通过加载特定类/使用特定类加载器/使用特定 JVM 设置/在序列化期间执行某些操作来打破这种行为?

对于不以java.* 开头的包中的类的序列化实例,可以使用ObjectInputStream 中的不同类加载器(例如here)来破坏。

对于 java.* 中的类,如您的情况 (java.lang.Class),只有 Bootstrap 类加载器可以加载它们,并且每个类加载器的类定义都是唯一的(由 JVM spec 保证)

换句话说,我能否在我的应用程序中依赖这种行为来序列化和反序列化 Class 对象

是的

【讨论】:

  • 当然Classes 被类加载器缓存,令我惊讶的是反序列化在另一个 JVM 实例中创建的Class 保留了与@987654331 的身份@ 当前 JVM 实例中的实例。因此,如果我使用ObjectInputStream 的标准反序列化逻辑,仅使用单个类加载器并且对具有相同规范名称的类没有不同的定义,那么我可以确定Class 对象的身份将在反序列化后保留吗?
  • 请注意,您所说的“类”实际上是类Class 的一个实例(抱歉绕口令)。因此,每个类加载器不能有多个实例代表同一个类 FQN。因此答案是肯定的,你可以肯定
  • 另请注意,如果版本不同,反序列化序列化对象(来自任何类,包括 Class)可能会导致错误...
  • 我刚刚创建了一个您可能感兴趣的答案:stackoverflow.com/a/35901086/4483113
  • 您好刚刚编辑了我的回复。 java.lang.Class不能被不同的类加载器加载,所以是有保证的
【解决方案2】:

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

它不需要实现readObject()writeObject() 来实现这一点,但它可以通过实现readResolve() 或通过ObjectInputStream 中的特殊逻辑来实现。

【讨论】:

  • 谢谢,但这应该是评论,而不是答案。我编辑了我的帖子,提到Class 也没有readResolve()
  • 这不是评论。我现在引用了这个答案所回答的问题。由于它似乎是一个错误的答案,我已经修改了它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-23
相关资源
最近更新 更多