目录
一、基本概念
1、定义
2、作用
二、序列化和反序列化的优缺点
1、优点
2、缺点
三、序列化使用场景
四、序列化与反序列化的注意事项
五、代码案例
一、基本概念
1、定义
序列化:java序列化是指对java对象转换为字节序列的过程
反序列化:java反序列化是指把字节序列恢复java对象的过程
2、作用
序列化的作用:在传递和保存对象时,保存对象的完整性和可传递性
对象转换为有序字节流,可以在网络上传输或则保存在本地文件中。
反序列化的作用:根据字节流中保存的对象状态及描述信息,通过反序列化重建对象。
二、序列化和反序列化的优缺点
1、优点
- 将对象转为字节流存储在磁盘上,当JVM停机的时候,字节流还会磁盘上等待,等下一次JVM启动,把序列化的对象,通过反序列化转为原来的对象,并且序列化的二进制序列减少存储空间
- 序列化转为字节流形式的对象可以进行网络传输
- 通过序列化可以在进程之间传递对象
2、缺点
- 无法跨语言
- 序列化后流的长度比通过缓冲区处理要大得多
- 序列化性能太低
三、序列化使用场景
1、分布式传递对象,或则网络传输,需要序列化
2、我调用你的jvm的方法,结果返回到我的jvm上进行处理
3、序列化可以保持对象的状态
4、数据传输并复原。在将j2ee中页面和后端使用的比较多。
5、远程调用,分布式存储,缓存存储
6、像银行卡,密码这些字段不能被序列化
四、序列化与反序列化的注意事项
1、java序列化的方式
- 实现Serializable接口,可以自定义writeObject,readObject,writeReplace,readResolve方法,会通过反射调用
- 实现Externalizable接口,需要实现writeExternal,readExternal方法
2、序列化ID问题
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类序列化ID是否一致(就是private static final long serialVersionUID = 1L;)
3、静态字段不会序列化
序列化时不保存静态变量,这是因为序列化保存的是对象的状态。静态变量是属于类的状态,因此序列化不保存静态变量。
4、transient
transient代表对象的临时数据。
如果你不想让对象中的某个成员被序列化可以在定义它的时候加上 transient 关键字进行修饰,这样,在对象被序列化时其就不会被序列化。
transient 修饰过的成员反序列化后将赋予默认值,即 0 或 null。
5、父类的序列化
当一个父类序列化,子类自动实现序列化,而子类实现Serializable接口,父类也需要实现Serializable接口
6、当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化
7、并非所有的对象都可以序列化
(1)安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行RMI传输等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的;
(2)资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分配,而且,也是没有必要这样实现
8、序列化解决深拷贝问题
如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存,这是用序列化深拷贝的重要原因。
五、代码案例
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import java.io.Serializable;
/**
* Describe: 用户实体
* Author: wang zhaoxian
* DATE: 2021/8/15.
*/
@AllArgsConstructor
@Data
@ToString
@NoArgsConstructor
public class User implements Serializable {
public static final long serialVersionUID = 1L;
private Integer id;
private String name;
private transient String password;
}
package com.xian.transi;
import com.xian.dto.User;
import org.junit.Test;
import java.io.*;
/**
* Describe:
* Author: wang zhaoxian
* DATE: 2021/8/21.
*/
public class TransientTest {
@Test
public void transientTest(){
try {
this.SerializableUser();
this.DeSerializableUser();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
public void SerializableUser() throws IOException {
User user = new User(1,"zhaoxian","123456");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D://data.txt"));
oos.writeObject(user);
oos.close();
System.out.println("普通序列化:userName:"+user.getName());
System.out.println("transient关键字序列化:password:"+user.getPassword());
/**
* 普通序列化:userName:zhaoxian
* transient关键字序列化:password:123456
*/
}
public void DeSerializableUser() throws IOException, ClassNotFoundException {
File file = new File("D://data.txt");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
User user = (User)ois.readObject();
System.out.println("普通反序列化:userName:"+user.getName());
System.out.println("transient关键字反序列化:password:"+user.getPassword());
/**
* 普通反序列化:userName:zhaoxian
* transient关键字反序列化:password:null
*/
}
}