一:概述
简单来说就是:保存(持久化)对象及其状态到内存或者磁盘
出现原因:Java 平台允许我们在内存中创建可复用的 Java 对象,但一般情况下,只有当 JVM 处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比 JVM 的生命周期更长
。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象
。
Java 对象序列化就能够帮助我们实现该功能
序列化对象以字节数组保存,所以静态成员不保存
使用 Java 对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,
对象序列化保存的是对象的”状态”
,即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
作用
:除了在持久化对象时会用到对象序列化之外,当使用 RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化
二:实现序列化的JavaAPI
可以被序列化的类需要有的条件:在 Java 中,只要一个类实现了 java.io.Serializable 接口
,那么它就可以被序列化
实现序列化及反序列化的对象:
- 序列化:ObjectOutputStream
- 反序列化:ObjectInputStream
实现自定义序列化策略:writeObject 和 readObject
三:serialVersionUID
虚拟机是否允许反序列化:不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID)
四:Transient关键字
Transient 关键字阻止该变量被序列化到文件中
:
- 在变量声明前加上 Transient 关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
- 服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全
举例简单来说就是:在将敏感数据序列化时需要有解密的密钥才可以进行序列化,否则的话便可以使用Transient进行阻止
五:使用
5.1 类实现Serializable接口
定义一个Person类,实现Serializable接口
import java.io.Serializable;
public class Person implements Serializable {
/**
* 序列化ID
*/
private static final long serialVersionUID = -5809782578272943999L;
private int age;
private String name;
private String sex;
public int getAge() {
return age;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
}
5.2 序列化对象
序列化Person类对象
private static void SerializePerson() throws FileNotFoundException,
IOException {
Person person = new Person();
person.setName("gacl");
person.setAge(25);
person.setSex("男");
// ObjectOutputStream 对象输出流,将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
new File("E:/Person.txt")));
oo.writeObject(person);
System.out.println("Person对象序列化成功!");
oo.close();
}
5.3 反序列化对象
反序列化Person类对象
private static Person DeserializePerson() throws Exception, IOException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
new File("E:/Person.txt")));
Person person = (Person) ois.readObject();
System.out.println("Person对象反序列化成功!");
return person;
}
六:serialVersionUID的作用
serialVersionUID: 字面意思上是序列化的版本号,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量
serialVersionUID有两种生成方式:
- Add default serial version ID
- Add generated serial version ID:这种方式生成的serialVersionUID是根据类名,接口名,方法和属性等来生成的
显式地定义serialVersionUID有两种用途:
3. 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同
的serialVersionUID;
4. 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同
的serialVersionUID。