Java中的序列化与反序列化

java中的序列化与反序列化

1.何为序列化&反序列化?
1) 序列化:将对象转换为字节的过程。
2) 反序列化:将字节转换为对象的过程。

2.序列化的应用场景?
1) 网络通讯
2) 数据存储(例如文件,缓存)

3.Java 中的对象的序列化与反序列化?
1) 对象要实现Serializable接口
2) 添加序列化id(为反序列化提供保障)
3) 借助流对象实现序列化和反序列化?

4.Java 中的序列化存在安全问题如何解决?
1) 添加writeObject(ObjectOutpuStream out)方法对内容进行加密再执行序列化。
2) 添加readObject(ObjectInputStream in)方法对内容先进行反序列化然后在执行解密操作。

5.Java 中序列化的粒度如何控制?
1) Transient (当少量属性不需要序列化时,使用此关键字修饰)
2) Externalizable(当只有少量属性需要序列化时实现此接口然后自己进行序列化操作,但是要序列化的对象必须时public修饰。)

6.序列化版本ID的真实用途:
当实体中增加属性后,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID。在例子中,如果没有指定Person类的serialVersionUID的,那么java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件多一个空格,得到的UID就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,添加了一个字段后,由于没有显指定serialVersionUID,编译器又为我们生成了一个UID,当然和前面保存在文件中的那个不会一样了,于是就出现了2个序列化版本号不一致的错误。因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法或者属性可以用。可以说serialVersionUID是序列化和反序列化之间彼此认识的唯一信物。

7.JDK类库中的序列化API
java.io.ObjectOutputStream代表对象输出流,它的writeObject(Objectobj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。
  
对象序列化包括如下步骤:
  1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
  2) 通过对象输出流的writeObject()方法写对象。
  对象反序列化的步骤如下:
  1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
  2) 通过对象输入流的readObject()方法读取对象。

示例:

package com.java.serializable;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class SysLog implements Serializable {
	private static final long serialVersionUID = -6695311142916641655L;
	private Integer id;
	private transient Integer time;

	public Integer getTime() {
		return time;
	}

	public void setTime(Integer time) {
		this.time = time;
	}

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	// 序列化定义的一种规范方法:用于对象序列化
	private void writeObject(ObjectOutputStream out) throws IOException {
		System.out.println("==writeObject==");
		// 对数据加密
		id = id + 1;
		// 对对象执行序列化
		out.defaultWriteObject();
	}

	// 序列化定义的一种规范方法:用于对象反序列化
	private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
		System.out.println("==readObject==");
		// 执行反序列化
		in.defaultReadObject();
		// 执行解密操作
		id = id - 1;
	}

}

public class TestSerializable01 {
	public static void main(String[] args) throws Exception {
		// 1.构建一个文件对象?
		File file = new File("data.dat");
		// 2.将日志对象序列化到文件
		doMethod01(file);
		// 3.从文件中读取对象
		doMethod02(file);
	}

	public static void doMethod02(File file) throws Exception {
		// 1.构建流对象,读取文件
		ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
		// 2.读取对象
		SysLog log = (SysLog) in.readObject();
		System.out.println(log.getId());
		System.out.println(log.getTime());
		// 3.释放资源
		in.close();
	}

	// 序列化//提取方法 alt+shift+m
	private static void doMethod01(File file) throws IOException, FileNotFoundException {
		// 2.1 构建日志对象
		SysLog log = new SysLog();
		log.setId(100);
		log.setTime(1000);
		// 2.2 构建对象流对象
		ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
		// 2.3执行对象的序列化
		out.writeObject(log);
		// 2.4.释放资源
		out.close();
		System.out.println("序列化ok");
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值