Java I/O 流之对象流中的序列化和反序列化

一、概念

当两个进程远程通信时,彼此可以发送各种类型的数据。 无论是何种类型的数据,都会以二进制序列的形式在网络上传送。比如,我们可以通过 http 协议发送字符串信息;我们也可以在网络上直接发送 Java 对象。发送方需要把这个 Java 对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为 Java 对象才能正常读取。把 Java 对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为 Java 对象的过程称为对象的反序列化。
在这里插入图片描述

对象序列化的作用有如下两种:

持久化: 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中,比如:休眠的实现。以后服务器 session 管理,hibernate 将对象持久化实现。
网络通信: 在网络上传送对象的字节序列。比如:服务器之间的数据通信、对象传递。

一个程序运行时所创建的对象是存储在内存空间里的,那如何对对象进行持久化的存储呢,我们可以用序列化流(ObjectOutputStream)将对象写入文件中从而持久化存储,当然java也提供了反序列化流(ObjectInputStream)将已经序列化的对象重新读取使用。

  • Serializable:java.io.Serializable 接口是一个可序列化认证接口,
    需要序列化的类必须实现此接口,否则将会报NotSerializableException异常。

ObjectOutputStream 序列化流

  • 构造方法

ObjectOutputStream(OutputStream out);// 传入一个OutputStream节点流
  • 方法

Object WriteObject();	//使用节点流写入对象

ObjectInputStream 反序列化流

  • 构造方法

ObjectInputStream(InputStream in);	//传入一个InputStream节点流
  • 方法

Object readObject();  //使用节点流写入对象

使用Properties类存储键值对并写入本地文件

// 序列化流存储
public static void stroe() throws IOException{
	
	// 目的地
	FileOutputStream fos = new FileOutputStream("D:/io1227/bb/cat.ob");
	// 创建序列化流
	ObjectOutputStream oos = new ObjectOutputStream(fos);
	// 写入对象
	oos.writeObject(new Cat("green", 1));	// Cat类必须要实现Serializable接口,下文有详细解释
	// 释放资源
	oos.close();
}
// 反序列化流
public static void getOb() throws IOException, ClassNotFoundException{
	
	// 目的地
	FileInputStream fis = new FileInputStream("D:/io1227/bb/cat.ob");
	// 反序列化流
	ObjectInputStream ois = new ObjectInputStream(fis);
	// 从文件中解析对象
	Cat cat = (Cat)ois.readObject();// 注意!返回值为Object,需要强制转型
	System.out.println(cat.toString());
	// 释放资源
	ois.close();
}

通过上面的代码通过序列化流和反序列化流实现了最基本的序列化和反序列化,但是又出现新的问题

InvalidClassException异常问题

当一个对象被序列化后,对象所对应的类只要做改动重新编译生成class文件,此时反序列化就会报InvalidClassException异常,这正是上述所需要的实现的Serializable接口导致的,
因为每当类重新编译,Serializable就会生成新的serialVersionUID,而序列化时将此时的serialVersionUID同时写入文件中,从而保证反序列化的正确,当class文件serialVersionUID改变导致不匹配,就会出现上述错误,我们可以通过定死serialVersionUID的方式来解决这个问题

private static final long serialVersionUID=123L;
// final表示该量为常量
// 因为声明的是Long类型,不要忘记数字后加L

有些属性不想被序列化怎么办

这个问题有两个解决方法

  1. 使用static修饰该属性,这是因为static锁修饰的属性和方法时属于静态共享区而不属于任何对象的,因此不会被序列化。
  2. 使用瞬态关键字transient修饰该属性,这是为序列化而量身定做的关键字,表示不需要被序列化。
posted @ 2022-08-29 20:05  司徒小夜  阅读(48)  评论(0编辑  收藏  举报