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

JAVA序列化基础知识Serializable与Externalizable

    博客分类:
  • java
阅读更多
大家都知道Serializable是一个mark interface,告诉JVM这个对象可以被转换成二进制流来传输.
但是Serializable与Externalizable的转换二进制流的过程是不一样的.
Serializable 在我们实现这个接口的时候,我们可以使用4个私有方法来控制序列化的过程:
  我们来看一个例子:
public class FooImpl implements java.io.Serializable{   
private String message;   
   
public String getFoo() {           
    return message;   
}   
   
public void setMessage(String message) {   
    this.message = message;   
}   
   
private void writeObject(java.io.ObjectOutputStream out) throws IOException {   
    System.out.println("writeObject invoked");   
    out.writeObject(this.message == null ? "hohohahaha" : this.message);   
}   
   
private void readObject(java.io.ObjectInputStream in) throws IOException,   
        ClassNotFoundException {   
    System.out.println("readObject invoked");   
    this.message = (String) in.readObject();   
    System.out.println("got message:" + message);   
}   
   
private Object writeReplace() throws ObjectStreamException {   
    System.out.println("writeReplace invoked");   
    return this;   
}   
   
private Object readResolve() throws ObjectStreamException {   
    System.out.println("readResolve invoked");   
    return this;   
}   
   
public Object serialize() throws IOException, ClassNotFoundException {   
    ByteArrayOutputStream baos = new ByteArrayOutputStream();   
    ObjectOutputStream oos = new ObjectOutputStream(baos);   
    oos.writeObject(this);   
    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());   
    ObjectInputStream ois = new ObjectInputStream(bais);   
    return ois.readObject();   
}   
        public static void main(String[] args) throws IOException,    
             ClassNotFoundException {   
                 FooImpl fooimpl = new FooImpl();   
                 fooimpl.serialize();   
}  

我们运行这段代码看到的debug信息:
writeReplace invoked
writeObject invoked
readObject invoked
readResolve invoked


当进行序列化的时候:
首先JVM会先调用writeReplace方法,在这个阶段,我们可以进行张冠李戴,将需要进行序列化的对象换成我们指定的对象.
跟着JVM将调用writeObject方法,来将对象中的属性一个个进行序列化,我们可以在这个方法中控制住哪些属性需要序列化.

当反序列化的时候:
JVM会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性,反序列化回来.
然后在readResolve方法中,我们也可以指定JVM返回我们特定的对象(不是刚刚序列化回来的对象).

注意到在writeReplace和readResolve,我们可以严格控制singleton的对象,在同一个JVM中完完全全只有唯一的对象,控制不让singleton对象产生副本.


Externalizable 是一个有实际方法需要实现的interface,包括writeExternal和readExternal:
   public class FooImpl implements java.io.Externalizable {   
    private String message;   
   
    public String getFoo() {   
        return message;   
    }   
   
    public void setMessage(String message) {   
        this.message = message;   
    }   
   
    private Object writeReplace() throws ObjectStreamException {   
        System.out.println("writeReplace invoked");   
        return this;   
    }   
   
    private Object readResolve() throws ObjectStreamException {   
        System.out.println("readResolve invoked");   
        return this;   
    }   
   
    public Object serialize() throws IOException, ClassNotFoundException {   
        ByteArrayOutputStream baos = new ByteArrayOutputStream();   
        ObjectOutputStream oos = new ObjectOutputStream(baos);   
        oos.writeObject(this);   
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());   
        ObjectInputStream ois = new ObjectInputStream(bais);   
        return ois.readObject();   
    }   
   
    public void readExternal(ObjectInput arg0) throws IOException,   
            ClassNotFoundException {   
        System.out.println("readExternal invoked");   
        Object obj = arg0.readObject();        
    }   
   
    public void writeExternal(ObjectOutput arg0) throws IOException {   
        System.out.println("writeExternal invoked");   
        arg0.writeObject("Hello world");   
    }   
         public static void main(String[] args) throws IOException,    
              ClassNotFoundException {   
                  FooImpl fooimpl = new FooImpl();   
                  fooimpl.serialize();   
    }   
}  


我们运行这段代码看到的debug信息:
writeReplace invoked
writeExternal invoked
readExternal invoked
readResolve invoked
在此writeExternal 和readExternal 的作用与writeObject和readObject 一样.

最后,当我们同时实现了两个interface的时候,JVM只运行Externalizable 接口里面的writeExternal 和readExternal 方法对序列化内容进行处理.
需要注意的是:Serializable是一个真正的mark interface,
writeObject,readObject, writeReplace,readResolve是直接与JVM通信,告诉JVM序列化的内容.



1.关键字transient
当一个成员被声明为transient时,在对象被保存的时候,该成员将不被保存。

2. 通过实现了Externalizable接口来产生Serialize功能
1)    在保存对象时不会保存任何成员对象。但我们可以手工保存成员对象(下面将讲到)。
2)    Default构造函数必须为public。因为在次第读取对象时,会调用default构造函数。因为对象中的成员对象不一定会被保存,所以要通过构造函数来进行初始化。
3)    Extrenalizable接口有writeExternal(ObjectOutput)和readExternal(ObjectInput)两个函数。在对实现了Externalizable接口的类进行次第读写时,会调用这两个函数。但是在恢复对象时,是先调用default构造函数再调用readExternal()函数的。

3.  Externalizable接口和Serializable接口的区别
1)    通过实现Serializable接口的方法,在保存对象时会把对象中所包含的成员对象也保存下来;而通过实现Externalizable接口的方法,在保存对象时不会保存任何成员对象。
2)    通过实现Serializable接口的方法,在恢复对象时不会调用任何构造函数(包括default构造函数);而通过实现Externalizable接口的方法,在恢复对象时会调用default构造函数。然后再调用readExternal()函数。
3)    利用writeExternal()和readExternal()函数来控制成员对象

4.  Java的怪异之处
1)    在下面的代码中我们可以看到,Blip3只实现了Serializable接口,而该接口只是个标志接口,所以这两个函数并不是接口的一部分。
2)    这两个函数被声明为private,按理只能在它们所在的类中被调用,但事实却是它们能被ObjectOutputStream和ObjectInputStream对象的writeObject()和readObject()函数调用。
3)    当调用ObjectOutputStream.writeObject(Object)时,传入的Serializable对象会被检查是否实现自己的writeObject(ObjectOutputStream)。如果有,就会执行扩增的writeObject(ObjectOutputStream)函数。当调用ObjectInputStream.readObject()时的工作过程也一样。
4)   在扩增的writeObject(ObjectOutputStream)中我们可以通过调用defaultWriteobject()函数来执行缺省的writeObject();在扩增的readObject(ObjectInputStream)函数中,我们可以通过调用defaultReadObject()函数来执行缺省的readObject()。在相应的缺省函数中都只对non-transient成员对象进行操作。
5.  关于Serialize的扩充话题
1)   当多个对象被保存到同一个Stream时,如果这些对象的成员对象中有指向相同的第三对象的reference,那么在恢复时也将指向同一个对象。但不相同的两个Stream中的对象的则不同。
分享到:
评论

相关推荐

    Java 串行化(序列化)Serializable/Externalizable

    在 serializable-prj 项目中,可能包含了各种示例代码,展示了如何在Java中实现和使用序列化功能。 综上所述,Java的序列化和外部化是实现对象持久化和跨进程通信的关键技术。理解并熟练掌握这些概念,能够帮助...

    java序列化和反序列化的方法

    在 Java 中,序列化和反序列化是通过实现 Serializable 接口来实现的。Serializable 接口是一个标记接口,不包含任何方法,但它告诉 Java虚拟机(JVM)该类可以被序列化。 在上面的代码中,我们可以看到 ...

    Java序列化(Serializable)与反序列化__1.docx

    Java序列化(Serializable)是Java平台提供的一种持久化机制,允许将对象的状态转换为字节流,以便存储到磁盘、数据库中,或者在网络上传输。这一过程被称为对象的序列化。反之,将字节流恢复为原来的对象状态称为反...

    Java序列化(Serializable)与反序列化_.docx

    ### Java序列化(Serializable)与反序列化详解 #### 序列化概念与应用场景 序列化是指将程序中的对象转换为一系列字节序列的过程,主要用于保存对象的状态以便将来使用或者在网络之间传输对象。Java提供了内置的...

    java.io.Serializable序列化问题

    除了 `Serializable` 接口之外,Java 还提供了 `Externalizable` 接口来控制序列化过程。`Externalizable` 继承自 `Serializable`,并定义了两个方法: 1. `void writeExternal(ObjectOutput out)`:用来指定对象...

    java对象序列化.ppt

    要实现对象序列化,Java类必须实现`Serializable`接口或`Externalizable`接口。`Serializable`接口是一个空接口,当一个类实现它时,表明该类的所有实例都可以被序列化。而`Externalizable`接口提供了更多的控制权,...

    Java对象序列化标准最新版

    ### Java对象序列化标准知识点详解 #### 一、系统架构概览 **1.1 概览** Java 对象序列化是一种将Java对象的状态转换成字节流的过程,以便于在网络上传输或存储到磁盘上。Java序列化标准定义了一套规则来描述如何...

    Java实现序列化例子

    在这种情况下,可以考虑使用`writeObject()`和`readObject()`方法来自定义序列化行为,或者使用`Externalizable`接口,它比`Serializable`提供了更多的控制。 6. **序列化框架**:除了Java内置的序列化机制,还有...

    java序列化与反序列化

    序列化的实现依赖于`java.io.Serializable`接口。如果一个类想要支持序列化,只需让该类实现这个接口,无需提供任何方法。实现此接口后,Java的默认序列化机制会遍历对象的所有字段并将其写入字节流。请注意,静态...

    Java 文件 序列化 读写

    在Java中,`java.io.Serializable`接口用于标记那些可以被序列化的类。下面将详细介绍Java文件序列化读写的相关知识点。 1. **序列化的目的**: - **持久化对象**:将对象状态保存到文件或数据库中,即使程序关闭...

    Java中的序列化与反序列化.pdf

    总结来说,Java中的序列化和反序列化是通过`Serializable`接口和`Externalizable`接口来实现的。`Serializable`接口是默认的序列化方式,适用于大多数简单情况;而`Externalizable`接口则提供了自定义序列化行为的...

    探索Java序列化与反序列化的奥秘:数据持久化的桥梁

    ### Java序列化与反序列化的深入解析 #### Java序列化的重要性及应用场景 Java序列化是一项核心功能,它允许程序员将对象的状态转化为字节流的形式,从而实现对象的持久化存储或者在网络之间进行传递。这对于诸如...

    java序列化和反序列化1

    - **Externalizable**:继承自Serializable接口,提供更细粒度的控制,允许开发者自定义序列化和反序列化的行为。 4. **序列化和反序列化步骤** - **序列化**: - 创建`ObjectOutputStream`,可以传入一个其他...

    java序列化方式Java系列2021.pdf

    Java序列化主要有两种方式:隐式序列化(实现Serializable接口)和显式序列化(实现Externalizable接口)。 ### 隐式序列化 **实现Serializable接口**:这是最常见也是最简单的一种序列化方式。只要一个类实现了`...

    JAVA对象的序列化与反序列化详细PPT课件.pptx

    另外,还有`java.io.Externalizable`接口,它继承自`Serializable`,但提供了更细粒度的控制权,允许类自定义序列化和反序列化的行为。如果一个类实现了`Externalizable`,则需要手动实现`writeExternal...

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

    `Serializable`接口是标识对象是否可序列化的标志,`Externalizable`接口允许更精细的控制序列化过程。 5.3 实施过程: 5.3.1 序列化:通过实现`Serializable`接口,然后使用`ObjectOutputStream`的`writeObject()`...

    java序列化对象的存储和读取共6页.pdf.zip

    在Java中,要实现一个对象的序列化,该类必须实现`java.io.Serializable`接口,这是一个标记接口,不包含任何方法。 1. **什么是序列化:** 序列化是将对象转换为字节序列的过程,这个字节序列可以被保存到磁盘、...

    Java 对象序列化详解以及实例实现和源码下载

    Java中的序列化机制有两种实现方式: 一种是实现Serializable接口 另一种是实现Externalizable接口 区别: 实现Serializable接口 1 系统自动储存必要的信息 2 Java内建支持,易于实现,只需实现该接口即可,无须任何...

Global site tag (gtag.js) - Google Analytics