类实现Serializable接口的目的是为了可持久化,比如网络传输或本地存储,为系统的分布和异构部署提供先决支持条件。若没有序列化,现在我们熟悉的远程调用、对象数据库都不可能存在。
先来看一个简单的序列化类:
import java.io.Serializable;
/**
* Created by 1 on 2018/8/20.
*/
public class Person implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
这是一个简单的JavaBean,实现了Serializable接口,可以在网络上传输,也可以本地存储然后读取。这里我们以Java消息服务(Java Message Service)方式传递该对象(即通过网络传递一个对象),定义在消息队列中的数据类型为ObjectMessage,首先定义一个消息的生产者(Producer):
public class Producer {
public static void main(String[] args) throws Exception{
Person person = new Person();
person.setName("混世魔王");
//序列化,保存到磁盘上
SerializableUtils.writeObject(person);
}
}
这里引入了一个工具类SerializableUtils,其作用是对一个类进行序列化和反序列化,并存储到硬盘上(模拟网络传输):
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* Created by 1 on 2018/8/23.
*/
public class SerializableUtils {
private static String FILE_NAME = "c:/obj.bin";
//序列化
public static void writeObject(Serializable s) {
try {
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream(FILE_NAME));
oos.writeObject(s);
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//反序列化
public static Object readObject() {
Object obj = null;
try {
ObjectInput input =
new ObjectInputStream(new FileInputStream(FILE_NAME));
obj = input.readObject();
input.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
}
通过对象序列化过程,把一个对象从内存块转化为可传输的数据流,然后通过网络发送到消息消费者(Consumer)手中,并进行反序列化,生成实例对象:
public class Consumer {
public static void main(String[] args) throws Exception{
//反序列化
Person person = (Person) SerializableUtils.readObject();
System.out.println("name = " + person.getName());
}
}
这就是一个反序列化过程,也就是对象数据列转换为一个实例对象的过程。
SerialVersionUID也叫做流标识符(Stream Unique Identifier),即类的版本定义,它可以显示声明也可以隐式声明,生成的依据是通过包名、类名、继承关系、非私有的方法和属性,以及参数、返回值等诸多因子计算得出的。JVM在反序列化时会比较数据流中的SerialVersionUID与类的SerialVersionUID是否相同,如果相同,则认为类没有发生改变,可以把数据流load为实例对象;如果不相同,抛出InvalidClassException异常。这样可以保证一个对象即使在网络或磁盘中实现类的一致性。