【序列化】lipp chan学习笔记

序列化与反序列化


一、目的

为了方便对象IO传输
在这里插入图片描述
在这里插入图片描述

1.1 作用

当两个进程在远程通信时候,可以发送各种类型的数据,包括jpg、mp4、mp3等媒体文件,这些数据会以二进制序列的形式进行传送。当两个java进程在通信时候,java需要序列化和反序列化进行进程间的对象传送。
例如发送方需要将java对象序列化成二进制字节序列,IO传输;接收方通过二进制字节序列读取出发送方传递的java对象。


二、序列化:将 Java 对象转换成字节流的过程


2.1 序列化过程:

是指把一个 Java 对象变成二进制内容,实质上就是一个 byte[]。
因为序列化后可以把 byte[] 保存到文件中,
或者把 byte[] 通过网络传输到远程(IO)
,如此就相当于把 Java 对象存储到文件或者通过网络传输出去了。

2.2 重点

Java 对象要能序列化,必须实现一个特殊的java.io.Serializable接口,
接口是一个标识空接口,没有定义任何方法,就是为了标识对象可以序列化。

如果要序列化的某些对象未实现java.io.Serializable接口,则此方法将引发NotSerializableException

三、反序列化:将字节流转换成 Java 对象


3.1 反序列化过程:

把一个二进制内容(也就是 byte[] 数组)变回 Java 对象。
通过反序列化,保存到文件中的 byte[] 数组又可以“变回” Java 对象,
或者从网络上读取 byte[] 并把它“变回” Java 对象。

3.2 作用

  • 以对象形式将数据存储到磁盘上,例如Redis存储对象列表。
  • 将程序状态保存在磁盘上,例如将巫师三存档。
  • 通过网络以表单对象发送数据,例如在聊天app以对象形式发送信息。

四、序列化工作原理

上文说到,我们只需要将对象实现序列化标识接口,
该对象就有资格进行序列化。
真正的序列化对象,jvm帮我们进行该类的对象写入持久性存储
或通过网络进行读取。

当然我们也可以通过ObjectInputStreamObjectOutputStream对象IO流类实现序列化和反序列化操作。

五、serialVersionUID常数


serialVersionUID 是一个常数,用于唯一标识可序列化类的版本。
从输入流构造对象时,JVM 在反序列化过程中检查此常数。如
果正在读取的对象的 serialVersionUID 与类中指定的序列号不同,
则 JVM 抛出InvalidClassException。
这是为了确保正在构造的对象与具有相同 serialVersionUID 的类兼容。

serialVersionUID 是可选的。如果不显式声明,Java 编译器将自动生成一个。

为什么要显示声明serialVersionUID?

因为java编译器会对要序列化的java对象跟据器类的元素计算UID,有一个改变,
serialVersionUID会随之改变。那如果,一个程序将某个对象序列化到文件中,
没有为其声明显式UID,那更新类后,比如添加个有参构造函数,
那自动生成的UID都变了,那先前序列化的java对象UID都不同,就没法反序列化成功了。

六、瞬时变量 transient


如果成员变量不需要序列化,则可以将其标记为瞬态。这意味着在序列化对象时不会存储 瞬时变量的值。 ## 七、例子 Student类
package day627.serial;

import java.io.Serializable;

public class Student implements Serializable {
	//显式UID
	private static final long serialVersionUID = 1014100089306623762L;
	// 姓名
	private String name;
	// 年龄
	//将年龄设置为瞬时变量
	private transient Integer age;

	public Student() {
	}

	public Student(String name, Integer age) {
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Integer getAge() {
		return age;
	}

	public void setAge(Integer age) {
		this.age = age;
	}

	@Override
	public String toString() {
		// 优化toString方法
		StringBuilder sb = new StringBuilder();
		sb.append("[").append("name = ").append(this.name).append(", ").append("age =").append(this.age).append("]");
		return sb.toString();
	}

}

测试类

package day627.serial;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;

public class Test01 {
	public static void main(String[] args) throws Exception {
		Student s = new Student();
		System.out.println(s);
//创建对象操作流 --> 序列化
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\lipp\\company\\obj.txt"));
//创建集合,且添加学生对象
		ArrayList<Student> list = new ArrayList<Student>();
		list.add(new Student("悔创阿里杰克马", 51));
		list.add(new Student("会点一点长几颗", 26));
		list.add(new Student("容颜老去蒋青青", 32));
		list.add(new Student("将里最丑刘一飞", 27));
//将集合写入到文件
		oos.writeObject(list);
//创建对象输入流 --> 反序列化
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\lipp\\company\\obj.txt"));
//读取数据
		Object o = ois.readObject();
//向下转型
		ArrayList<Student> al = (ArrayList<Student>) o;
//遍历集合
		for (int i = 0; i < al.size(); i++) {
//根据索引取出集合的每一个元素
			Student stu = al.get(i);
			System.out.println(stu);
		}
	}
}

result

[name = null, age =null]
[name = 悔创阿里杰克马, age =null]
[name = 会点一点长几颗, age =null]
[name = 容颜老去蒋青青, age =null]
[name = 将里最丑刘一飞, age =null]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值