1 序列化与反序列化
序列化就是在保存数据时,保存数据的值和数据类型;
反序列化就是在恢复数据时,恢复数据的值和数据类型;
需要让某个对象支持序列化机制,则必须让其类是可序列化的;
为了让某个类是可序列化的,该类必须实现 Serilizable与 Externalizable 两个接口之一。
❓ 为什么需要对象处理流?
答:假设我们存储了 int num = 20这个数据到文件中,而这个20是一个数字,我们需要从文件中将数据恢复。
可是,文件中仅仅存储了 20 这一个数字,我们没有办法判断,存储它的时候是将它存储为了 int 类型还是 String 类型。
而对象处理流,就是帮助我们解决类似问题的,即:能够将 基本数据类型 或者 对象 进行序列化和反序列化操作!
2 对象处理流
2.1 概述
ObjectOutputStream 提供 序列化功能;
ObjectInputStream 提供 反序列化功能。
提供了对基本类型或者对象类型的序列化和反序列化方法。
类的继承关系图如下:
2.2 ObjectOutputStream案例
使用ObjectOutputStream序列化基本数据类型和一个Student对象(name,age),保存到data.dat文件中。
⌨️ 参考代码与结果:
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; /** * @author 兴趣使然黄小黄 * @version 1.0 * 序列化基本数据类型和对象类型演示 */ public class ObjectOutputStreamTest { public static void main(String[] args) { //创建流对象 ObjectOutputStream objectOutputStream = null; try { objectOutputStream = new ObjectOutputStream(new FileOutputStream( "D:\\Ideaproject2021\\JavaSE\\src\\IOchapter\\data.dat")); //序列化后,保存的文件格式,不是纯文本,而是按照它自己的格式存储的 //序列化数据 //int -> Integer(实现了 Serializable) objectOutputStream.writeInt(100); //boolean -> Boolean(实现了 Serializable) objectOutputStream.writeBoolean(true); //char -> Character objectOutputStream.writeChar('a'); //String objectOutputStream.writeUTF("黄小黄"); //保存一个Student对象 objectOutputStream.writeObject(new Student("黄小黄", 21)); System.out.println("数据序列化成功!"); } catch (IOException e) { e.printStackTrace(); } finally { //释放资源 if(objectOutputStream != null) { try { objectOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } } class Student implements Serializable{ private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } }
🐦 说明:
序列化基本数据类型的时候,会进行自动装箱。比如存储int类型的100,则会以Integer的形式自动装箱后存储,因为Integer实现了Serializable接口。
2.3 ObjectInputStream案例
使用ObjectInputStream读取data.dat的数据,并反序列化恢复数据。
⌨️ 参考代码与结果:
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; /** * @author 兴趣使然黄小黄 * @version 1.0 */ public class ObjectInputStreamTest { public static void main(String[] args) { //创建流对象 ObjectInputStream objectInputStream = null; try { objectInputStream = new ObjectInputStream(new FileInputStream( "D:\\Ideaproject2021\\JavaSE\\src\\IOchapter\\data.dat")); //读取数据 System.out.println(objectInputStream.readInt()); System.out.println(objectInputStream.readBoolean()); System.out.println(objectInputStream.readChar()); System.out.println(objectInputStream.readUTF()); System.out.println(objectInputStream.readObject()); //程序结束 System.out.println("反序列化完成!"); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } finally { //释放资源 if (objectInputStream != null){ try { objectInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
🐱 说明:
反序列化的顺序一定要与序列化的顺序一样,否则,程序会抛出异常。
2.4 对象处理流的使用细节
读写顺序一致,即序列化与反序列化的顺序应该一致;
要求实现序列化或者反序列化对象,需要实现Serializable接口;
序列化类中建议添加SerialVersionUID,为了提高版本兼容性;
序列化对象时,默认将里面所有的属性都进行序列化,但static与transient修饰的成员除外;
序列化对象时,要求里面的属性的类型也要实现序列化接口;
序列化具备可继承性,也就是如果某类已经实现了序列化,则它的所有子类也已经默认实现了序列化。