相关文章:
- 《IO流 (一) ----- 基本概念和File类》
- 《IO流 (二) ----- 文件流》
- 《IO流 (三) ----- 字符流和字符缓冲流》
- 《IO流 (四) ----- 转换流和标准字节输出流》
- 《IO流 (五) ----- 对象数据的序列化和反序列化》
本篇涉及内容
-
对象的序列化和反序列化的概念
-
序列化版本号的介绍
-
用对象流实现对象的序列化和反序列化
一、关于对象的序列化和反序列化的概念

注意:
- 对象流是一个包装流,需要通过其他输入输出流来创建对象流。
- 参与序列化和反序列化的对象必须实现Serializable接口。
二、关于序列化版本号
-
通过代码发现,Serializable这个接口中什么代码都没有,但是它有什么作用呢?
起到标识的作用,该接口是一个标志接口,当java虚拟机看到了类实现了该接口后,会为该类自动生成一个序列化版本号。
-
那么序列化版本号有什么用呢?
- 当一个类实现类Seializable接口后, 该类进行编译时,java虚拟机会为该类自动生成一个默认的序列化版本号,但是如果之后再对这个类的代码进行修改,序列化版本号就会变化,如果用修改后的新的类的引用去指向从以前保存的序列化对象数据的文件反序列化出来的对象则会产生异常:java.io.InvalidClassException,所以从某种意义上来说一个类的序列化版本号就可以用来区分类。
- java语言中用什么机制来区分类?
(1) 首先通过类名进行对比,如果类名不一样,那么肯定不是同一个类。
(2) 如果类名一样,则通过序列化版本号来区分。
-
默认生成序列化版本号的缺点
- 根据上面所述,如果修改了一个类中的代码,那么其序列化版本号会产生变化,对于我们修改之前序列化出来的对象数据文件来说就无法正常读取了。
- 改进:凡是一个类实现类Serializable接口,建议给该类提供一个固定不变的序列化版本号,这样即便是修改类中的代码,序列化版本号也不会改变,java虚拟机始终认为它是同一个类,之前的序列化对象文件数据也能够进行正常读取。
- 序列化版本号示例:
private static final long serialVersionUID = 24253252352129776L;
-
使用IDEA自动生成序列化版本号
(1) 先按照下图设置打勾
(2) 之后在对应的类中鼠标指向类名,快捷键:option + 回车键
,可以自动生成一个序列化版本号。
三、对象的序列化和反序列化
-
通过ObjectOutputStream实现对象的序列化
User user1 = new User("莫莫",8); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user1")); oos.writeObject(user1); oos.flush();// flush后会生成一个user1文件 oos.close();
-
通过ObjectInputStream实现对象的反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user1")); User user1 = (User) ois.readObject(); System.out.println(user1);// User{name='莫莫', age=8} ois.close();
-
序列化和反序列化多个对象
思路:将多个对象放在集合中,然后序列化、反序列化集合。List list = new ArrayList<>(); list.add(new User("莫莫", 8)); list.add(new User("考拉", 7)); list.add(new User("芋头", 6)); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("users")); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("users")); // 将集合序列化 oos.writeObject(list); oos.flush(); oos.close(); // 将集合反序列化 List<User> getList = (List<User>) ois.readObject(); for (User user : getList) { System.out.println(user); } /* * User{name='莫莫', age=8} * User{name='考拉', age=7} * User{name='芋头', age=6} * */ ois.close();
-
transient关键字
作用:"transient"翻译为“游离的”,当你不希望给对象中的某个属性(字段)进行序列化时,把该关键字加到其前面即可。我们把User类中的age属性添加上
transient
关键字。private String name; private transient int age;
再重新运行上面的程序,则会出现:
User{name='莫莫', age=0} User{name='考拉', age=0} User{name='芋头', age=0}