什么是序列化

(1)序列化是将对象转变为字节序列的过程,反序列化则是将字节序列恢复为对象的过程。

(2)对象序列化保存的是对象的状态,即它的成员变量;

(3)对象的持久化存储(写文件),网络传输对象,或者使用RMI都会用到对象序列化。

JAVA 提供的操作序列化的接口

(1)Java 主要提供给了两个接口实现对象的序列化和反序列化,java.io.ObjectInputStream的readObject()方法 和 java.io.ObjectOutputStream 的writeObject(Object obj)方法;

(2)只有实现Serializable或Externalizable接口的类的对象才能被序列化;否则会抛出java.io.NotSerializableException异常。

JAVA对象序列化示例

序列化的过程

首先创建 ObjectOutputStream 对象,该对象可以包装其他输出流,比如文件输出流;

调用对象输出流的writeObject(Object obj)方法,可以将对象写入到输出流中。

关闭流。结束。

对象持久化到文件中的过程结束。

反序列化的过程:

首先创建ObjectInputStream对象,类似于ObjectOutputStream;

调用对象输入流的readObject()方法,读对象到输入流中。返回字节序列转化的对象。

关闭流;结束。

输出:

result

(2)transient 关键字
当某个成员变量声明为transient后,默认的序列化机制就会忽略该变量。

除了上面提到的两个方法外:
private void writeObject(java.io.ObjectOutputStream out) throws IOException ;

private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;

还有其他三个方法,可供我们定制自己的序列化反序列化过程:

private void readObjectNoData() throws ObjectStreamException;

ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException;

ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;

readObjectNoData() :用于初始化反序列化对象,当发生一些情况导致反序列化对象不能获得数据时调用;

writeReplace() :指派其他对象写入序列化的流中;
readResolve():返回的对象替换反序列化创建的实例;

总结:

当进行序列化的时候:

首先JVM会先调用writeReplace方法,在这个阶段,我们可以进行张冠李戴,将需要进行序列化的对象换成我们指定的对象.

跟着JVM将调用writeObject方法,来将对象中的属性一个个进行序列化,我们可以在这个方法中控制住哪些属性需要序列化.

当反序列化的时候:

JVM会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性,反序列化回来.

然后在readResolve方法中,我们也可以指定JVM返回我们特定的对象(不是刚刚序列化回来的对象).

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

(3)类实现Externalizable 接口
Externalizable 接口继承 Serializable接口:

public interface Externalizable extends Serializable ;

Serializable接口是一个mark interface,没有实际方法;而Externalizable 接口提供了两个方法:

void readExternal (ObjectInput in) ;

void writeExternal (ObjectOutput out) ;

readExternal (ObjectInput in):从输入流中读取内容恢复对象;

writeExternal (ObjectOutput out) : 写入对象到输出流中;

Externalizable
使用Externalizable进行序列化时,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。因此,必须提供一个无参构造器,访问权限为public;否则会抛出java.io.InvalidClassException 异常;

总结:Externalizable接口实现的功能与Serializable接口类似,Serializable序列化时不会调用默认的构造器,而Externalizable序列化时会调用默认构造器;