java序列化与反序列化

java对象转换为字节序列,序列化。

字节序列恢复为java对象,反序列化。

java.io.ObjectOutputStream 代表输出流,它的writeObject(Object obj)对指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流。

java.io.ObjectInputStream代表输入流,它的readObject()方法从一个源输入流中读取字节,再把它们反序列化为一个对象。

只有实现了Serializable和Externalizable接口的类对象才能被序列化,否则ObjectOutputStream的writeObject(Object obj)将抛出IOException。

Externalizable继承了Serializable接口,实现了Externalizable完全由自身来控制序列化的行为,而仅仅实现了Serializable的类采用默认的方式进行

序列化。

 

如果按照默认方式序列化,如果一个ObjectOutputStream对象多次序列化同一对象,那么由一个ObjectInputStream对象对象反序列化的也是同一个对象。

如果按照ObjectOutputStream的默认方式序列化,静态变量和transient变量都没有被序列化,当ObjectInputStream按照默认方式反序列化的时候,有

如下特点:

1.如果内存中对象所属的类还没有被加载,那么先加载并初始化这个类。如果classpath中不存在相应的文件,那么会抛出ClassNotFoundException。

2.反序列化不会调用类的任何构造方法。

 

序列化对象图

如果一个对象Customer有一个name和Set<Order>属性,那么序列化的时候,会把name和set都序列化,抽象地讲,将序列化直接引用和间接引用的对象。

 

控制序列化行为

方法:

private void writeObject(java.io.ObjectOutputStream out)throws IOException;

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

如果序列化一个对象,如果该对象有writeObject()方法的时候,就执行这个方法,否则执行默认序列化方法。

在这个对象的writeObject方法中,可以先调用ObjectOutputStream的defaultWriteObject()方法,使得输出流先执行默认的序列化操作。

如果反序列化一个对象,如果该对象有readObject()方法的时候,就执行这个方法,否则执行默认序列化方法。

在这个对象的readObject方法中,可以先调用ObjectInputStream的defaultReadObject()方法,使得输出流先执行默认的反序列化操作。

值得注意的是,以上的readObject()方法和writeObject()方法并不是在java.io.Serializable接口中定义的。

 

当一个软件系统想要拓展第三方java类库(JDK类库)的功能时,最常见的方式是实现第三方类库的接口,或者创建类库中抽象方法的子类。但

以上writeObject()和readObject()方法并不是在java.io.Serializable接口中定义。JDK类库的设计人员并没有把这两个方法放在Serializable中,

这样做的优点在于:

1.不必公开这两个方法的访问权限,以便封装序列化的细节。如果这两个方法放在Serializable中,就必须定义为public类型。

2.不必强迫用户定义的可序列化类实现这两个方法。如果把这两个方法放在Serializable接口中,它的实现类就必须实现这些

方法,否则就只能声明为抽象类。

 

以下情况,可以考虑采用用户自定义的序列化方式,从而控制序列化的行为:

1.确保序列化的安全性,对敏感的信息进行加密后再序列化,在反序列化的时候需要解密。

2.确保对象的成员变量符合正确的约束条件。

3.优化序列化的性能。

4.便于更好地封装类的内部数据,确保类的接口不会被类的内部实现所束缚。

 

Serializable接口单例

序列化单例,反序列化后就存在不止一个单例对象,为此,要增加方法

private Object readResolve() throws ObjectStreamException;

与此相对应的方法有

private Object writeReplace()。

 

 

 

实现externalizable接口

public void writeExternal(ObjectOutput out) throws IOException;

public void readExternal(ObjectInput in)throws IOException,ClassNotFoundException;

writeExternal()方法负责序列化操作,readExternal()负责反序列化操作。

实现了Externalizable接口的类的对象进行反序列化时,会先调用类的不带参数的构造函数,这个和默认的反序列化方式不同。

 

 

序列化与版本

默认的serialVersionUID,不同编译器,可能相同,也可能不同。

显示的serialVersionUID

在某些场合,希望类的不同版本对序列化兼容,因而需要确保不同的版本需要有相同的serialVersionUID.

在某些场合,不希望不同版本对序列化兼容,因而需要确保类的不同版本需要有不同的serialVersionUID.

用serialVersionUID来控制序列化兼容的能力是有限的。当一个类的不同版本的serialVersionUID相同,仍然可能出现

序列化不兼容的情况。因为序列化兼容不仅取决于serialVersionUID,还取决于类的不同版本的实现细节和序列化细节。

java序列化与反序列化,布布扣,bubuko.com

java序列化与反序列化

上一篇:第149天学习打卡(Kubernetes 部署nginx 部署Dashboard)


下一篇:Mac 停掉自带的Apache服务