先看看概念介绍:
- 序列化:把对象转换为字节序列的过程称为对象的序列化。
- 反序列化:把字节序列恢复为对象的过程称为对象的反序列化。
应用场景
- 数据的持久化。简单的说,就是把jvm中的对象的状态写入到硬盘里
- 网络之间的通信。把网络这端的对象此刻的属性状态通过序列化成字节,网络另一端接收到字节转换成对象。
让我们用代码加深理解吧
一、这是一个要被序列化和反序列化的类:
/**
*需要传输或持久化的java对象,实现Serializable接口
*
*/
import java.io.Serializable;
public class SerializableBean implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String param;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
}
二、这是一个把SerializableBean序列化和反序列化的类:
/**
*
*把SerializableBean序列化和反序列化的类
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializableTest {
public static void main(String[] args) {
String path = "D://SAFile";
// 实例化SerializableBean,设置值
SerializableBean sa = new SerializableBean();
sa.setName("Cyf");
sa.setParam("test");
// 写入文件
try {
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(path));
oos.writeObject(sa);
} catch (IOException e) {
e.printStackTrace();
}
//读取文件输出
File file = new File(path);
FileInputStream fis;
try {
fis = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fis);
SerializableBean invsa = (SerializableBean) ois.readObject();
System.out.print(invsa.getClass() + " "
+ invsa.getName() + " "
+ invsa.getParam());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
1.第一段代码中,首先我们定义了一个实现Serializable接口的SerializableBean类,这个类中有name和param属性。
2.第二段代码中,分为两部分:一部分是实例化SerializableBean类,并设置属性值,然后把这个类序列化持久化到D盘中;另一部分是反序列化并输出这个对象的属性值。
序列化和反序列化的扩展点
1.serialVersionUID的值
需要被序列化和反序列化的对象设置一个serialVersionUID值:
private static final long serialVersionUID = 1L;
这个值就如同序列化和反序列化之间的版本约定。举个例子:如果我先把反序列化部分代码屏蔽,在序列化的时候设置SerializableBean类的serialVersionUID值为1L,然后屏蔽序列化部分代码,在反序列化的时候设置SerializableBean类的serialVersionUID值为2L,就会报错:
java.io.InvalidClassException:
local class incompatible: stream classdesc serialVersionUID = 1,
local class serialVersionUID = 2
2.transient
若我们在SerializableBean类中增加一个用transient修饰的属性:
private transient String constant;
public String getConstant() {
return constant;
}
public void setConstant(String constant) {
this.constant = constant;
}
在序列化之前设置constant值
sa.setConstant("CONSTANT");
在反序列化部分代码中修改输出:
System.out.print(invsa.getClass() + " "
+ invsa.getName() + " "
+ invsa.getParam() + " "
+ invsa.getConstant());
输出结果:
class com.test.SerializableBean Cyf test null
constant的值为null。
可以得出用transient修饰的属性将不被序列化。
3.Externalizable
Externalizable继承Serializable,扩展了writeExternal(),readExternal()这两个方法。
若我们直接把SerializableBean类实现接口改成Externalizable,序列化和反序列化之后的输出是:
class com.test.SerializableBean null null null
我们发现,之前的三个属性的值都没被序列化。
那么如何来设置属性值呢?
这时候就要用到writeExternal(),readExternal()这两个方法了:
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(name);
out.writeObject(param);
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
name = (String) in.readObject();
param = (String) in.readObject();
}
再次输出:
class com.test.ExternalizableBean Cyf test
序列化和反序列化End。