序列化与反序列化的代码讲解
基本实现
这里我们可以先跑一跑代码,看一看。
Run SerializationTest.java
Run UnserializationTest.java
前文我们说,序列化与反序列化的根本目的是数据的传输。
- SerializationTest.java
咱们来想象一个有趣的小实验:把Java对象变成魔法饼干存进罐子里!
你心爱的玩具需要保存起来,方便下次继续玩
- 【准备魔法罐子】首先咱们要找一个透明的密封罐(FileOutputStream),用来装我们的魔法饼干
FileOutputStream
就像个透明玻璃罐,用来存放最终的成果:"ser.bin"就是我们的魔法饼干罐 - 【施展序列化魔法】然后拿出神奇裱花袋(ObjectOutputStream),把裱花嘴套在罐口上
ObjectOutputStream
就像能把对象变成数据流的神奇工具,接在罐子上准备输出 - 【注入对象精华】最后像挤奶油一样,把Java对象"滋溜"一下挤进罐子!
oos.writeObject(obj) 这一瞬间,你的对象就被转化成魔法数据,永久保存在二进制文件里啦~
下次想找回玩具时,用ObjectInputStream
这个反向魔法,就能把饼干变回原来的玩具对象啦!就像这样:
java
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
Object recoveredToy = ois.readObject();
Serializable 接口
(1) 序列化类的属性没有实现 Serializable 那么在序列化就会报错
想象你要参加「对象王国」的狂欢派对,入场券就是这个Serializable接口!🎫
▶️ 特点:
-
空白的魔法契约
public class MagicCookie implements Serializable { ... }
- 只需在类头顶上贴上这个标签(
implements Serializable
) - 不用写任何魔法咒语(不需要实现任何方法)
- 就像拿到一张「免笔试入场券」
- 只需在类头顶上贴上这个标签(
-
自动触发魔法阵
javaoos.writeObject(cookie); // ✨ 自动施放序列化咒语
- Java会悄悄检查你的「入场券」
- 如果没贴标签?→ 抛出InvalidClassException(就像被保安拦在派对门外!)
java
public class Person implements Serializable { // 🎯 正确佩戴许可证!
private String name;
private int age;
}
当删除implements Serializable
时:
java
public class Person { // 😱 许可证被偷了!
private String name;
private int age;
}
👉 后果:运行时会弹出超恐怖的红色警告!
Exception in thread "main" java.io.NotSerializableException: src.Person
就像你试图带着普通书包穿越时空隧道,被守卫机器人用激光枪拦截!
终极比喻记忆法 🧩
- Serializable → 免费基础会员卡(躺平就能用)
- Externalizable → VIP定制服务(需要自己动手配置)
- 未实现接口 → 想带宠物进电影院却没买宠物票(一定会被拦下!)
- JVM → 严格的时空管理局警察(检查你的证件!)
此外,如果我们此处将 Serializable 接口删除掉的话,会导致如下结果。
(2) 在反序列化过程中,它的父类如果没有实现序列化接口,那么将需要提供无参构造函数来重新创建对象。
(3)一个实现 Serializable 接口的子类也是可以被序列化的。
(4) 静态成员变量是不能被序列化
序列化是针对对象属性的,而静态成员变量是属于类的。
(5) transient 标识的对象成员变量不参与序列化")(5) transient 标识的对象成员变量不参与序列化
这里我们可以动手实操一下,想这么一个问题
- 如何让Java对象的敏感信息"瞬间消失"?
🎯 任务背景
你是一名Java特工,需要护送Person
对象穿越「序列化隧道」到另一个系统。但有个致命问题 :
⚠️ **name
是绝密信息,绝对不能泄露!**
怎么办?快用transient
隐身喷雾!
🕶️ STEP 1:装备隐身喷雾(修改Person类)
打开Person.java
,找到第7行秘密武器库:
java
// 原版(危险!名字会被记录)
private String name;
// 特工改造版 → 喷上transient隐身喷雾!
private transient String name; // 🕶️ 隐身模式启动
💻 STEP 2:执行加密传输(序列化测试)
运行SerializationTest.java
,观察特工日志:
java
// 序列化前的对象状态
Person{name='aa', age=22}
// 穿越序列化隧道后...
System.out.println("序列化文件内容:");
// 用hex编辑器查看ser.bin → name字段已消失!🚀
🔓 STEP 3:接收端解密验证(反序列化测试)
运行UnserializeTest.java
,发现惊人变化:
java
// 反序列化后的对象
Person{name='null', age=22}
// ❗ name变成null,但age完好无损!
🚀 完整特工代码(SerializationTest.java
java
package com.tingjun;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class SerializationTest {
public static void serialize(Object obj) throws IOException {
// 🕶️ 创建序列化隧道入口
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
oos.close(); // 重要!关闭资源
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
// 🎯 特工代号设置
Person person = new Person("aa", 22);
System.out.println("【特工出发前状态】");
System.out.println(person); // Person{name='aa', age=22}
// 🚀 启动序列化传送
serialize(person);
// 🔍 接收端反序列化检测
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin"));
Person deserializedPerson = (Person) ois.readObject();
ois.close();
System.out.println("\n【穿越序列化隧道后】");
System.out.println("序列化文件内容:"); // ✨ 关键输出位置!
System.out.println(deserializedPerson); // Person{name='null', age=22}
}
}
上述说的还是关于序列化本身的一些特性,明天我们接着讲一讲序列化的安全问题是如何产生的。