如何自行实现序列化。意思是我不希望我的类实现可序列化。但我想自己实现序列化。因此,如果不实现可序列化,我可以通过网络传输对象或将它们写入文件,然后在相同的状态下检索它们。我想这样做,因为我想学习和探索事物。
答案 0 :(得分:6)
序列化是将对象结构转换为另一种格式的过程,该格式可以很容易地通过网络传输或者可以存储在文件中。 Java将对象序列化为二进制格式。如果带宽/磁盘空间不是问题,则不需要这样做。您可以简单地将对象编码为XML:
// Code is for illustration purpose only, I haven't compiled it!!!
public class Person {
private String name;
private int age;
// ...
public String serializeToXml() {
StringBuilder xml = new StringBuilder();
xml.append("<person>");
xml.append("<attribute name=\"age\" type=\"int\">").append(age);
xml.append("</attribute>");
xml.append("<attribute name=\"name\" type=\"string\">").append(name);
xml.append("</attribute>");
xml.append("</person>");
return xml.toString();
}
现在,您可以获取对象的XML表示形式,并将其“序列化”为文件或网络连接。用任何语言编写的可以解析XML的程序都可以将该对象“反序列化”为自己的数据结构。
如果需要更紧凑的表示,可以考虑二进制编码:
// A naive binary serializer.
public byte[] serializeToBytes() {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
// Object name and number of attributes.
// Write the 4 byte length of the string and the string itself to
// the ByteArrayOutputStream.
writeString("Person", bytes);
bytes.write(2); // number of attributes;
// Serialize age
writeString("age", bytes);
bytes.write(1); // type = 1 (i.e, int)
writeString(Integer.toString(age), bytes);
// serialize name
writeString("name", bytes);
bytes.write(2); // type = 2 (i.e, string)
writeString(name, bytes);
return bytes.toByteArray();
}
private static void writeString(String s, ByteArrayOutputStream bytes) {
bytes.write(s.length());
bytes.write(s.toBytes());
}
要了解更紧凑的二进制序列化方案,请参阅Google Protocol Buffers的Java实现。
答案 1 :(得分:1)
您可以使用Externalizable并实现自己的序列化机制。序列化的一个难点是版本控制,因此这可能是一项具有挑战性的练习。您还可以将protobuf和Avro视为二进制序列化格式。
答案 2 :(得分:1)
你从反思开始。获取对象的类以及其类和所有超类的声明字段。然后获取每个字段的值并将其写入dump。
反序列化时,只需反转进程:从序列化表单中获取类名,实例化对象并根据转储设置其字段。
如果您只想学习,那就是简单的方法。如果你想“真实地”做这件事,可能会出现很多问题:
答案 3 :(得分:0)
获取Java源代码并了解序列化的实现方式。我在一个月前做过这个,现在有一个序列化只使用16%的空间和20%的“正常”序列化时间,代价是假设编写序列化数据的类没有改变。我将它用于客户端 - 服务器序列化,我可以使用这个假设。
答案 4 :(得分:0)
作为@Konrad Garus回答的补充。有一个问题是完全重新实现Java序列化的显示阻止。
反序列化对象时,需要使用对象的类的构造函数之一来重新创建实例。但是你应该使用哪个构造函数?如果有一个no-args构造函数,你可以想象使用它。但是,除了创建它之外,no-args构造函数(或实际上任何构造函数)可能会对该对象执行某些操作。例如,它可能会向已创建新实例的其他内容发送通知...传递尚未完全反序列化的实例。
实际上,复制标准的Java反序列化代码确实很困难。它的作用是:
问题是第2步涉及一些普通Java类不允许做的“黑魔法”。
(如果您想了解血腥细节,请阅读序列化规范并查看OpenJDK代码库中的实现。)