Java基础(15):IO流—掌握对象序列化和反序列化操作

        在网络通信中,任何数据都是以二进制的形式来传输的,而对象序列化可以把内存中的Java对象转成二进制流,而二进制流可以存放在本地磁盘文件中,通过网络或者程序来获取该二进制流后,都能将该二进制流恢复成Java对象。序列化的这一过程就是将对象状态信息转换为可存储或传输的过程。

对象序列化的作用:

  • 对象序列化可以把对象以字节序列的形式永久保存在磁盘中。
  • 对象序列化可以用于在网络中传输对象。
  • 对象序列化使得对象可以脱离程序的运行而独立存在。

序列化与反序列化:

序列化是将一个Java对象写入IO流中,转换成字节序列,而反序列化是用IO流将字节序列恢复成Java对象。
如果要让对象序列化,则该对象的类必须实现接口 serializable, 该接口没有任何方法,仅作标记,用于代表该类可以实现序列化。
如果序列化的对象类型是别的类,则该类也要实现序列化接口,保证序列化过程中用到的类都要实现序列化,不然会出现异常。

对象序列化需要的IO流:

  • ObjectOuputStream:该输出流是处理流,需要节点流作为参数。使用该流的writeObject()将一个对象序列化。
  • ObjectInputStream:该输入流是处理流,需要一个节点输入流作为参数,使用readObjec()把读取的字节序列(二进制数据)恢复成Java对象。

对象序列化的过程:

  1. 使用ObjectOuputStream,
  2. 调用ObjectOuputStream中的writeObject()把对象转换成字节序列
  3. 代码演示对象序列化:

public class Person implements Serializable{
	private String name;
	private int age;
	private String sex;
	
	public Person(String name, int age, String sex) {
		this.name = name;
		this.age = age;
		this.sex = sex;
	}/**省略setter 和 getter*/
}

//把对象写入序列化文件
public class Test {
    public static void main(String[] args) throws Exception {
	FileOutputStream fos = new FileOutputStream("D:\\Object01.txt");//存放对象字节序列的文件路径
	//对象输出流中的节点流是一个缓冲流,该流包装节点流,所以需要flush()
	ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos)); 
	Person p = new Person("张三", 15, "男");
	oos.writeObject(p);
	oos.flush();	
    }	
} 

对象反序列化的过程:

  1. 使用ObjectInputStream
  2. 调用ObjectInputStream的readObject()方法读取流中的对象
  3. 代码演示反序列化:
FileInputStream fis = new FileInputStream("D:\\Object01.txt");
		//创建一个ObjectInputStream输入流,节点流数据源是一个对象序列化文件
		ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
		//读取Person对象
		Person p = (Person)ois.readObject();
		System.out.println(p.getName() + "||" + p.getAge() +"||" + p.getSex());


反序列化简单小结:

  • 反序列化读取的数据不是一个Java类,所以使用反序列化恢复Java对象后,需要保证该类存在,不然Java对象是没存在意义的。
  • 还有反序列化的对象没有使用构造器来初始化。可以自己往构造器中加入一条提示语句,运行该对象时查看是否运行。
  • 如果我们读取的二进制文件中存在多个对象,则必须按照他们序列化的顺序来读取,不然会出错。
  • 如果成员变量使用了transient修饰,那么将不会把该成员变量数据序列化。

测试序列化多个对象:

public class Person implements Serializable{
	private String name;
	private int age;
	private transient String sex; //透明化,表示该成员变量不会序列化
	
	public Person(String name, int age, String sex) {
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
    /** 省略getter 和 setter */
}
public class Test {
	public static void main(String[] args) throws Exception {
		//存放对象字节序列的文件路径
		FileOutputStream fos = new FileOutputStream("D:\\MoreObject.txt");
		//对节点流使用了缓冲流,所以需要flush()
		ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos)); 
		Person p = new Person("张三", 15, "男");
		Person p1 = new Person("李四", 20, "男");
		Person p2 = new Person("王五", 25, "男");
		//序列化多个对象
		oos.writeObject(p);
		oos.writeObject(p1);
		oos.writeObject(p2);
		oos.flush();
		
		//创建一个对象输入流ObjectInputStream
		FileInputStream fis = new FileInputStream("D:\\MoreObject.txt");
		ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
		//恢复多个对象
		Person per1 = (Person) ois.readObject();
		Person per2 = (Person) ois.readObject();
		Person per3 = (Person) ois.readObject();
//		Person per4 = (Person) ois.readObject(); //EOFException
		
		System.out.println(per1.getName() + "||" + per1.getAge() +"||" + per1.getSex());
		System.out.println(per2.getName() + "||" + per2.getAge() +"||" + per2.getSex());
		System.out.println(per3.getName() + "||" + per3.getAge() +"||" + per3.getSex());
		
//		输出结果:
//		张三||15||null
//		李四||20||null
//		王五||25||null
	}
}
  • 实例解析:
  1. 被transient修饰的成员变量sex,无法对数据序列化,所以输出结果中是null,因为该值是引用类型,如果是值类型就是系统默认的初始值。
  2. 恢复的对象顺序是和序列化对象一致的,这是因为反序列化文件有多个对象,恢复的顺序也是按照对象序列化时的顺序来恢复的。
  3. 如果序列化文件中的对象已经读取完了,再次readObject()会引发EOFException异常。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值