`
bluepopopo
  • 浏览: 91586 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

什么是writeObject 和readObject?可定制的序列化过程

    博客分类:
  • J2SE
阅读更多
这篇文章很直接,简单易懂。尝试着翻译一下 ,原文是What are writeObject and readObject? Customizing the serialization process.

在Java中使用Serialization相当简单。如果你有一些对象想要进行序列化,你只需实现Serializable接口。然后,你可以使用ObjectOutputStream将该对象保存至文件或发送到其他主机。所有的non-transient和non-static字段都将被序列化,并且由反序列化重构造出一模一样的对象联系图(譬如许多引用都指向该对象)。但有时你可能想实现你自己的对象序列化和反序列化。那么你可以在某些特定情形下得到更多的控制。来看下面的简单例子。
class SessionDTO implements Serializable {
    private static final long serialVersionUID = 1L;
    private int data; // Stores session data

    // Session activation time (creation, deserialization)
    private long activationTime; 

    public SessionDTO(int data) {
        this.data = data;
        this.activationTime = System.currentTimeMillis();
    }

    public int getData() {
        return data;
    }

    public long getActivationTime() {
        return activationTime;
    }
}

以下是序列化上述class到文件和其反序列化的主函数。
public class SerializeTester implements Serializable {
    public static void main(String... strings) throws Exception {
        File file = new File("out.ser");

        ObjectOutputStream oos = new ObjectOutputStream(
            new FileOutputStream(file));
        SessionDTO dto = new SessionDTO(1);
        oos.writeObject(dto);
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(
            new FileInputStream(file));
        SessionDTO dto = (SessionDTO) ois.readObject();

        System.out.println("data : " + dto.getData()
            + " activation time : " + dto.getActivationTime());
        ois.close();
    }
}

类SessionDTO展现的是要在两个服务器之间传输的session。它包含了一些信息在字段data上,该字段需要被序列化。但是它还有另外一个字段activationTime,该字段应该是session对象第一次出现在任意服务器上的时间。它不在我们想要传输的信息之列。这个字段应该在反序列化之后在赋值。进一步来说,没必要把它放在stream中在服务器中传递,因为它占据了不必要的空间。

解决这种情况可以使用writeObject和readObject。有可能你们有一些人没有听说过它们,那是因为它们在许多Java书籍中给忽略了,而且它们们也不是众多流行Java考试的一部分。让我们用这些方法来重写SessionDTO:
class SessionDTO implements Serializable {
    private static final long serialVersionUID = 1L;
    private transient int data; // Stores session data

    //Session activation time (creation, deserialization)
    private transient long activationTime; 

    public SessionDTO(int data) {
        this.data = data;
        this.activationTime = System.currentTimeMillis();
    }

    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();
        oos.writeInt(data);
        System.out.println("session serialized");
    }

    private void readObject(ObjectInputStream ois) throws IOException,
            ClassNotFoundException {
        ois.defaultReadObject();
        data = ois.readInt();
        activationTime = System.currentTimeMillis();
        System.out.println("session deserialized");
    }

    public int getData() {
        return data;
    }

    public long getActivationTime() {
        return activationTime;
    }
}

方法writeObject处理对象的序列化。如果声明该方法,它将会被ObjectOutputStream调用而不是默认的序列化进程。如果你是第一次看见它,你会很惊奇尽管它们被外部类调用但事实上这是两个private的方法。并且它们既不存在于java.lang.Object,也没有在Serializable中声明。那么ObjectOutputStream如何使用它们的呢?这个吗,ObjectOutputStream使用了反射来寻找是否声明了这两个方法。因为ObjectOutputStream使用getPrivateMethod,所以这些方法不得不被声明为priate以至于供ObjectOutputStream来使用。

在两个方法的开始处,你会发现调用了defaultWriteObject()和defaultReadObject()。它们做的是默认的序列化进程,就像写/读所有的non-transient和 non-static字段(但他们不会去做serialVersionUID的检查).通常说来,所有我们想要自己处理的字段都应该声明为transient。这样的话,defaultWriteObject/defaultReadObject便可以专注于其余字段,而我们则可为这些特定的字段(译者:指transient)定制序列化。使用那两个默认的方法并不是强制的,而是给予了处理复杂应用时更多的灵活性。

你可以从这里这里读到更多有关于序列化的知识。

自己再补充一些:

1.Write的顺序和read的顺序需要对应,譬如有多个字段都用wirteInt一一写入流中,那么readInt需要按照顺序将其赋值;

2.Externalizable,该接口是继承于Serializable ,所以实现序列化有两种方式。区别在于Externalizable多声明了两个方法readExternal和writeExternal,子类必须实现二者。Serializable是内建支持的也就是直接implement即可,但Externalizable的实现类必须提供readExternal和writeExternal实现。对于Serializable来说,Java自己建立对象图和字段进行对象序列化,可能会占用更多空间。而Externalizable则完全需要程序员自己控制如何写/读,麻烦但可以有效控制序列化的存储的内容。

3.正如Effectvie Java中提到的,序列化就如同另外一个构造函数,只不过是有由stream进行创建的。如果字段有一些条件限制的,特别是非可变的类定义了可变的字段会反序列化可能会有问题。可以在readObject方法中添加条件限制,也可以在readResolve中做。参考56条“保护性的编写readObject”和“提供一个readResolve方法”。

4.当有非常复杂的对象需要提供deep clone时,可以考虑将其声明为可序列化,不过缺点也显而易见,性能开销。

7
2
分享到:
评论
2 楼 凊颩蒣莱____ 2014-04-21  
最后怎么都是用了transient来修饰啊  这样不是都不会被序列化麽
1 楼 Wuaner 2012-09-12  
楼主翻译的真不错,赞 

marker interface这种古老的,严重背离低耦合高内聚原则的东西,就应该被annotation取代掉!

相关推荐

    WEBSphere反序列化漏扫.rar

    Java 序列化是指把 Java 对象转换为字节序列的过程,便于保存在内存、文件、数据库中,ObjectOutputStream类的 writeObject() 方法可以实现序列化。反序列化是指把字节序列恢复为 Java 对象的过程,...

    简易之手写序列化和反序列化框架

    个人理解,序列化和反序列化就是一种压缩和解压的过程。压缩和解压讲究一个速度和大小 2、translate 禁止序列化 3、破坏translate java 和file 、javaXML 都可以通过重写私有readObject和writeObject进行破坏...

    Java高级程序设计实战教程第五章-Java序列化机制.pptx

    Java高级程序设计 第5章 Java序列化机制 5.1 应用场景 5.2 相关知识5.3 实施过程 5.4 拓展知识5.5 拓展训练 5.6 课后小结5.7 课后习题 5.8 上机实训 Java高级程序设计实战教程第五章-Java序列化机制全文共15页,当前...

    Objective-C序列化框架KryoCocoa.zip

    KryoCocoa 是 Kryo 高性能 Java 序列化框架的 Objective-C 移植版本,兼容 Java 版本的序列化格式。示例代码:Kryo *kryo = [Kryo new]; // ... NSOutputStream *outputStream = [NSOutputStream ...

    Java对象序列化框架Kryo.zip

    Kryo 是一个快速高效的Java对象图形序列化框架,主要特点是性能、高效和易用。该项目用来序列化对象到文件、数据库或者网络。示例代码:Kryo kryo = new Kryo(); // ... Output output = new Output(new...

    Java快速序列化库FST.zip

    FST fast-serialization 是重新实现的 Java 快速对象序列化的开发包。序列化速度更快(2-10倍)、体积更小,而且兼容 JDK 原生的序列化。要求 JDK 1.7 支持。 Maven:  <groupId>de.ruedigermoeller  ...

    J2SE中的序列化的认识

    在ObjectInputStream 和ObjectOutputStream的帮助下,我们可以轻松的实现序列化。 只要我们的class 实现了java.io.Serializable接口,就可以利用ObjectOutputStream的writeObject()方法将一个对象序列化;利用...

    人工智能-项目实践-搜索引擎-java实验1-实现搜索引擎的倒排索引数据结构

    第三是熟悉对象的序列化和反序列化 作为类的方法来实现下面二个方法 ◦public abstract void writeObject(ObjectOutputStream out); ◦public abstract void readObject(ObjectInputStream in); 要熟悉对文件,...

    基于Java实现学生选课模拟系统之文件输入输出【100011979】

    采用对象序列化的 readObject 方法从文件中恢复对象,并操作学生的选课课表,实现退课操作。 3.打印课程对象信息,采用覆盖定义 toString()方法的方式。 实验步骤 在保持实验三项目中,Course 类,Student 类,...

    大话PKG解包工具

    支持AS3的ByteArray序列化对象的AMF格式编码、解码( readObject、writeObject )。 支持AS3的ByteArray的compress、uncompress压缩算法:DEFLATE、LZIB、LZMA。 支持直接修改AS3的ByteArray字节流内编码的对象。 ...

    AMF数据分析器_V22

    支持AS3的ByteArray序列化对象的AMF格式编码、解码( readObject、writeObject )。 支持AS3的ByteArray的compress、uncompress压缩算法:DEFLATE、LZIB、LZMA。 支持直接修改AS3的ByteArray字节流内编码的对象。 ...

    Jayrock(json字符串解析)

    /// /// JSON反序列化 /// /// </summary> public static T JsonDeserialize(string jsonString) { DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T)); MemoryStream ms = new ...

    java 混淆工具,不可逆 jocky 也许是最好的了

    事实上,即便不加@preserve指令,Jocky对Java语言特有的一些private级别的方法不进行混淆,譬如,在序列化时有特殊作用的writeObject及readObject方法等。但笔者强烈建议: 针对这些有特殊含义不能够被混淆的 ...

    jocky 混肴编译rar包(ant和插件俩个版本)

    事实上,即便不加@preserve指令,Jocky对Java语言特有的一些private级别的方法不进行混淆,譬如,在序列化时有特殊作用的writeObject及readObject方法等。但笔者强烈建议: 针对这些有特殊含义不...

    JDK 1.5的泛型實現(Generics in JDK 1.5)

    serialization(序列化、次第讀寫) generics(泛型) polymorphism(多型) 全文提要 泛型技術與 Sun JDK的淵源可追溯自 JDK1.3。但無論 JDK 1.3或 JDK1.4,都只是 以編譯器外掛附件的方式來支援泛型語法,...

    joc eclipse plugin

    Jocky混淆编译器是在Sun JDK中提供的Java编译器(javac)的基础上完成的,修改了其中的代码生成过程,对编译器生成的中间代码进行混淆,最后再生成class文件,这样编译和混淆只需要一个步骤就可以完成。另外可以在源...

    miscellaneous

    Java****堆栈与堆内存: 对于类中的方法,... 为什么瞬态提供了自定义的readObject和writeObject方法,以实现比默认方法更好的序列化工作。 arraylist的创建方式:具有初始容量的公共arraylist。 可比者与比较者之间的

    录入输出系统

    录入输出项目,帮助网友解决问题:1、界面的切换,2、对象序列化问题ObjectInputStream ObjectOutputStream 储存数据用的记事本系列化对象的方法

    JAVA核心知识点整理(有效)

    MinorGC 的过程(复制->清空->互换) ....................................................................................... 24 1:eden、servicorFrom 复制到 ServicorTo,年龄+1.................................

Global site tag (gtag.js) - Google Analytics