概念
- 序列化是将对象转换为字节序列的过程(其中可以是二进制、特定的字符串、xml、json)。
- 反序列化是将字节序列恢复为对象的过程。
序列化使用场景
- 需要把内存中的对象保存到文件中或者数据库中(持久化)时候。
- 跨平台通过网络传输对象时候(WebService SOAP)。
- 通过RNI传输对象的时候 (仅限于java环境)。
实现序列化
实现序列化比较简单将需要序列化的类实现Serializable
即可。但是查看源码知道,Serializable
这个接口中没有方法,所以我们即可理解为一个标记,标记该类是可以被序列化的。
序列化实例
//对象类
import java.io.Serializable;
public class Student implements Serializable {
private static final long serialVersionUID = -1556557458139596779L;
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
//序列化方法
public static void serialize(Object obj,String outFile){
try {
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream(outFile));
//往磁盘中写入当前内存中对象的状态
oos.writeObject(obj);
oos.flush();
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//反序列方法
public static Object deSerialize(String readFile){
try {
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream(readFile));
Object obj =ois.readObject();
ois.close();
return obj;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
//调用
Student s = new Student("KKY",22);
String sFileName = "student.out";
serialize(s,sFileName);
Student sde=(Student) deSerialize("student.out");
System.out.println(sde);
默认序列化机制
如果仅仅只是让某个类实现Serializable接口,而没有其它任何处理的话,则就是使用默认序列化机制。但是默认序列化机制效率非常低,所以一般是不使用java默认序列化规则。
序列化ID
private static final long serialVersionUID = -1556557458139596779L;
序列化ID主要针对跨服务器、跨平台情况,如果序列化ID不一致就会无法反序列化,所以一般我们都需要去生成序列化ID。
其他注意点
指定不序列化
在属性上添加transient
关键字,即可指明该属性不被序列化,同时静态变量不能被序列化。但是如果想序列化transient
修饰的变量,就需要自定义序列化规则。虽然Serializable
没有定义方法,但是有三个方法可以自己实现来修改默认序列化规则:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException;
private void readObjectNoData()
throws ObjectStreamException;
所以即可修改如下:
transient private int age;
//JDK自动调用 扩展序列化规则一个方法
private void writeObject(ObjectOutputStream out) throws IOException{
out.defaultWriteObject();
out.writeInt(age);
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
in.defaultReadObject();
age = in.readInt();
}
上述也是可以序列化age
属性,不过这两个方法应该用于扩展序列化规则。
readResolve()方法
当我们使用单例模式时,本来是期望只生成一个对象实例,不过如果该类是可序列化的,那么情况就不一样了此时,我们可以增加对readResolve方法的实现,来确保在同一个JVM中只有一个单例对象的使用。
private Student() {
super();
}
private static final Student INSTANCE = new Student();
public static Student getInstance() {
return INSTANCE;
}
private Object readResolve()
throws ObjectStreamException {
return INSTANCE;
}
Externalizable接口
如果想自定义序列化内容可以实现Externalizable
接口。实现Externalizable
接口需要自己定义序列化和反序列化方法。
mport java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
//JDK将不会调用默认的序列化规则
//完全使用自定义序列化规则
public class Person implements Externalizable {
private String name;
private int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
//扩展序列化的方法
@Override
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
name = (String) in.readObject();
age = in.readInt();
}
@Override
public void writeExternal(ObjectOutput out)
throws IOException {
out.writeObject(name);
out.writeInt(age);
}
}
序列化前和序列化后的对象的关系
深复制。
网络环境中的序列化
java环境RMI Remote Method Invoker 远程方法调用
仅限于java平台中调用
序列化的效率非常低
WebService SOAP Simple Object Access Protrol 简单对象传出协议
跨语言、跨平台
还是没有解决效率低的问题
可读性非常差,基于xml传输的
JSON
跨语言、跨平台
可读性非常强
序列化效率有所提高,但目前来说还不是最高的
序列化发展方向
主要发展方向其实就是往更高性能和更小的传输大小。