对象流
对象流
ObjectOutputStream :ObjectOutputStream将Java对象的原始数据类型和图形写入OutputStream。
ObjectInputStream:ObjectInputStream反序列化先前使用ObjectOutputStream编写的原始数据和对象。
ObjectOutputStream / ObjectInputStream
- 增强了缓冲区功能
- 增强了读写8种基本数据类型和字符串的功能
- 增强了读写对象的功能
- readObject() 从流中读取一个对象
- writeObject(Object obj) 向流中写入一个对象
使用流传输对象的过程称为序列化、反序列化
ObjectOutputStream
小案例:
package com.iopractise; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; /** * 使用ObjectOutputStream实现对象的序列化 */ public class Demo08 { public static void main(String[] args) throws IOException { //1.创建对象流 FileOutputStream fos = new FileOutputStream("d:\\stu.bin"); ObjectOutputStream oos = new ObjectOutputStream(fos); //2.序列化(写入操作) Student stu1 = new Student("张三", 20); oos.writeObject(stu1); //3.关闭 oos.close(); System.out.println("序列化完毕"); /** * 如果student类没有实现Serializable会报没有序列化异常 * java.io.NotSerializableException */ } }
运行完毕之后,我们打开D盘下的stu.bin文件之后,会看到序列化之后的对象信息。(只不过是乱码的)
ͭ sr _x0016_com.iopractise.Student2"«?
I ageL namet _x0012_Ljava/lang/String;xp t 张三
ObjectInputStream
小案例:
package com.iopractise; import java.io.*; /** * 使用ObjectInputStream实现对象的反序列化(读取重构成对象) */ public class Demo09 { public static void main(String[] args) throws IOException, ClassNotFoundException { //1.创建对象流 FileInputStream fis = new FileInputStream("d:\\stu.bin"); ObjectInputStream ois = new ObjectInputStream(fis); //2.序列化(写入操作) Student student = (Student) ois.readObject(); //3.关闭 ois.close(); System.out.println("反序列化完毕"); System.out.println(student.toString()); } }
运行结果:
序列化完毕
Student{name='张三', age=20}
注意:
(1)如果 Student student = (Student) ois.readObject(); Student student2 = (Student) ois.readObject();连续读两次会抛出异常:java.io.EOFException,表示已经读完了,就不能再读了。
(2)如果实体类中又套用了其他的实体类,那么在序列化和反序列化的时候,这个套用的实体类也要实现Serializable,接口否则是会抛异常的。
(3)private static final long serialVersionUID = 1L;//这个值可以随便指定 这个序列化id表示的是序列化的类和反序列化的类是同一个类。这个时候,我们在执行反反序列化的类。会抛出异常:local class incompatible: stream classdesc serialVersionUID = 3603863914098147085, local class serialVersionUID = 1
解决办法也挺简单的,我们再重新执行一下序列化的类,然后再执行反序列化的类,也就是说重新序列化一次就好了。
(4)private transient int age;//如果我们对于那些不想序列化和反序列化的属性,我们可以使用transient 关键字进行修饰。transient 表示瞬时的,暂时的,如果能够序列化或者反序列化,那不就成了永久的了吗。
再次运行结果:序列化完毕
Student{name='张三', age=0};//可见age就没有被序列化。
(5)静态属性也是不能序列化或者反序列化的。比如;private static String country="中国";
(6)序列化多个对象的时候,可以借助集合来进行实现。
补充:(序列化多个对象的时候)
第一种实现方式:
//2.序列化(写入操作)
Student stu1 = new Student("张三", 20);
Student stu2 = new Student("李四", 25);
oos.writeObject(stu1);
oos.writeObject(stu2);
//2.反序列化(写入操作)
Student student = (Student) ois.readObject();
Student studen2 = (Student) ois.readObject();
//3.关闭
ois.close();
System.out.println("序列化完毕");
System.out.println(student.toString());
System.out.println(studen2.toString());
第二种实现方式:通过集合的方式实现:
//2.序列化(写入操作)
Student stu1 = new Student("张三", 20);
Student stu2 = new Student("李四", 25);
ArrayList<Student> stuList = new ArrayList<Student>();
stuList.add(stu1);
stuList.add(stu2);
oos.writeObject(stuList);
//3.关闭
oos.close();
System.out.println("序列化完毕");
//2.反序列化(写入操作)
ArrayList<Student> stuList = (ArrayList<Student>) ois.readObject();
//3.关闭
ois.close();
System.out.println("序列化完毕");
System.out.println(stuList.toString());