java序列化
序列化(也可叫做持久化)是指将对象的状态信息转化为可以存储或者传输的形式的过程,序列化后的信息可以暂时的放在存储区或者写入文件中。
反序列化是指将文件或存储区的信息转换为对象的形式。
什么情况需要需序列化?
- 当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;
- 当你想用套接字在网络上传送对象的时候;
- 当你想通过RMI传输对象的时候;
如何进行序列化和反序列化 ?
建立一个Emploee类实现java.io.Serializable接口。对于一个实体类,不想将所有的属性都进行序列化,有专门的关键字 transient 注明该属性是短暂的。
public class Employee implements Serializable {
/**
* 序列化版本号
*/
private static final long serialVersionUID = 2540986455050446094L;
public String name;
public String address;
public transient int SSN;
public int number;
}
写一个测试类将对象存储在D://serializable.ser中。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializableTest {
public SerializableTest() {
}
public static void main(String[] args) {
Employee employee = new Employee();
employee.name = "Reyan Ali";
employee.address = "Phokka Kuan, Ambehta Peer";
employee.SSN = 112233;
employee.number = 101;
try {
File file = new File("D://employee.ser");
FileOutputStream outputStream =
new FileOutputStream(file);
ObjectOutputStream objectOutputStream =
new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(employee);
objectOutputStream.close();
outputStream.close();
System.out.printf("Serialized data is saved in D://employee.ser");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
打开D盘(我存储在了D盘),
文件存在与D://employee.ser。
返序列化。
import java.io.File;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class DeSerrializable {
public static void main(String[] args) {
Employee employee = null;
try {
File file = new File("D://employee.ser");
FileInputStream inputStream =
new FileInputStream(file);
ObjectInputStream objectInputStream =
new ObjectInputStream(inputStream);
employee = (Employee) objectInputStream.readObject();
System.out.println("deserializable....");
System.out.println("name: "+employee.name);
System.out.println("address: "+employee.address);
System.out.println("number: "+employee.number);
System.out.println("SSN: "+employee.SSN);
inputStream.close();
objectInputStream.close();
}catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果为
deserializable....
name: Reyan Ali
address: Phokka Kuan, Ambehta Peer
number: 101
SSN: 0
结果也可以看出SSN属性由于使用了关键字transient并没有被序列化。
serialVersionUID的作用
serialVersionUID 简单来说就是这个类序列化的版本号,他在序列化和反序列化起到验证版本是否一致的作用,序列化时会将serialVersionUID 一并序列化到文件中,当反序列化时会将serialVersionUID 传送过来,系统会检测到serialVersionUID ,并将其与lei中的serialVersionUID 进行比较,如果是相同,就可以反序列化成功,不同则报异常。
java.io.InvalidClassException: com.xxxxxx; local class incompatible: stream classdesc serialVersionUID = 5590259895198052390, local class serialVersionUID = 7673969121092229700
serialVersionUID 版本号可以有两种方式生成
显式生成 :就是在类中以成员属性的形式定义。
例如:
//这种显式生成默认的serialVersionUID 默认都是1L
//这种方式生成的serialVersionUID 不唯一
private static final long serialVersionUID = 1L;
// 这种也是系统生成的
//但是是根据包名,类名,继承关系,非私有的方法和属性,以及参数,返回值等诸多因子计算得出的
//极度复杂生成的一个64位的哈希字段。基本上计算出来的这个值基本上是唯一的.
private static final long serialVersionUID = 2540986455050446094L;
隐式生成:在类的编译时生成,也是根据包名,类名,继承关系,非私有的方法和属性,以及参数,返回值等诸多因子计算得出的极度复杂生成的一个64位的哈希字段。但是这种serialVersionUID 并不是永久不变的,当类中的继承关系或者属性等发生改变时,重新编译会重新生成一个serialVersionUID,以前序列化的对象在反序列化时就会出现serialVersionUID不同的情况,导致反序列化不成功,报java.io.InvalidClassException异常。
所以在要序列化的对象所属的类,应显式去添加一个serialVersionUID。