【问题标题】:What exactly is serialized Class data?序列化的 Class 数据到底是什么?
【发布时间】:2017-11-30 22:36:17
【问题描述】:

我一直想知道你是否像这样在对象中序列化类数据:

public Something implements Serializable{
     private static final long serialVersionUID = 1L;
     public Class type;
}

哪些数据实际上被序列化并保存为type

即使您当时没有加载该类,是否也可以从 type 中获取 simplename 和 fullname 之类的信息?

【问题讨论】:

  • 你不应该使用原始类型。

标签: java class serialization


【解决方案1】:

即使您当时没有加载该类,是否可以从 type 中获取 simplename 和 fullname 之类的信息?

只要该类型的类存在,Class 对象所引用的类就会被加载。


使用下面的代码:

class Test implements Serializable {
    // verion UID

    public Class type;

    public Test(Class type) {
        this.type = type;
    }
}

我序列化了一个 Test 对象,其中包含不同类型的 ClassSecond

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("text.obj"));
out.writeObject(new Test(Second.class));
out.close();

现在,重新读一遍:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("text.obj"));
Test test = (Test) in.readObject();
in.close();

此代码中没有对Second 类的引用。如果在运行上述程序时加载了Second,我们可以认为这是由于反序列化而不是直接引用。

确实如此:

所以是的,尝试获取 type.getSimpleName() 之类的东西会起作用。

跑步:

ObjectInputStream in = new ObjectInputStream(new FileInputStream("text.obj"));
Test test = (Test) in.readObject();
System.out.println(test.type.getSimpleName());
in.close();

打印

Second

当您删除 Second 类时,您会按预期获得 ClassNotFoundException。通过阅读stacktrace,可以看到程序尝试加载Second类:

Exception in thread "main" java.lang.ClassNotFoundException: test.Second
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at java.io.ObjectInputStream.resolveClass(Unknown Source)
    at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
    at java.io.ObjectInputStream.readClassDesc(Unknown Source)
    at java.io.ObjectInputStream.readClass(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.defaultReadFields(Unknown Source)
    at java.io.ObjectInputStream.readSerialData(Unknown Source)
    at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
    at java.io.ObjectInputStream.readObject0(Unknown Source)
    at java.io.ObjectInputStream.readObject(Unknown Source)

【讨论】:

  • 谢谢,这非常详尽!稍微跟进一下:假设您在序列化对象中有一组不同的 Class 类型(项目中都缺少这些类型),我假设输入流会在遇到第一个异常时立即抛出异常,对吗?是否可以读取这些声明的数据?
  • @MoffKalast 是的,一旦它试图反序列化项目中不存在该类的对象,就会抛出异常。请问你为什么要探索这个?对象流往往会被滥用(用于可以使用不同工具更有效地完成的事情),如果不谨慎处理,序列化可能会导致扩展时出现问题(请参阅我在“What is the penalty for unnecessarily implementing Serializable”上的回答)
  • 好吧,我有大量包含类数据的序列化文件,作为识别组件的一种方式,我在修改实际类的包时需要保持兼容性。我最终修改了 ObjectInputStream ,因此它将类 simplename 与哈希图中的一个匹配,以防它在默认情况下找不到它(就像这个答案建议的那样:stackoverflow.com/a/3916282/4012132)。我最感兴趣的是其他想法,以及 Class 原始类型是可序列化的,而它包含的 Class 可能不是 - 再次加载时会导致一些奇怪的东西。
  • @MoffKalast 我创建了一个聊天,click here。我也许可以帮到你,希望能让你远离尝试修改序列化类型的麻烦
【解决方案2】:

简单:这将序列化该 Class 类中存在的所有非瞬态字段。

从这个意义上说:如果您真的关心细节,请转到 Class.java 的源代码。

第二个问题(如果可以反序列化无法加载的类) - 我做出有根据的猜测:我认为这应该失败。关键是:Class 对象将允许您查询字段、方法……如果不完全了解该类,这是不可能的。

但这应该很容易测试。万一今晚没有人想出更好的答案......我明天会检查并让你知道。

【讨论】:

    猜你喜欢
    • 2012-08-02
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-20
    • 2012-01-27
    • 1970-01-01
    • 2011-04-07
    相关资源
    最近更新 更多