序列化(写对象)与反序列化(读对象)
1、java.io.ObjectOutputStream extends OutputStream
对象的序列化流,把对象以流的方式写入文件
构造方法
构造方法 | 作用 |
---|---|
ObjectOutStream(OutputStream out) | 创建使用指定OutputStream的 ObjectOutputStream对象 |
参数:
OutputStream out :字节输出流
特有的一个成员方法
方法 | 作用 |
---|---|
void writeObject(Object obj) | 将指定的对象写入到ObjectOutputStream |
使用步骤
- 创建ObjectOutputStream对象,构造方法中传递字节输出流对象
- 使用ObjectOutputStream对象的writeObject方法,将指定对象写入ObjectOutStream
- close方法释放资源
package cn.zhuobo.day15.aboutObjectOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Demo01ObjectOutputStream {
public static void main(String[] args) throws IOException {
Person p1 = new Person("猪八戒", 360);
writeObject(p1);
}
private static void writeObject(Person p) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day15-code/writeObject.txt"));
oos.writeObject(p);
oos.close();
}
}
但是要注意的是:要要序列化或者反序列化的对象应该是实现了一个java.io.Serializable接口的
Serializable接口:是一个标记类,实现该接口的类会获得一个标记,用来标记对象可以序列化或者反序列化。这个接口内部其实什么也没有,就仅仅是标记作用的标记类。没有实现该接口的类的对象要序列化就会抛出 NotSerializableException。
public class Person implements Serializable {
// body
}
2、java.io.ObjectInputStream extends InputStream
对象的反序列化流,把文件保存的对象以流的方式读取出来
构造方法
构造方法 | 作用 |
---|---|
ObjectInputStream(InputStream in) | 创建一个从指定的 InputStream对象中读取的ObjectInputStream |
参数:
InputStream in : 字节输入流
特有的成员方法
方法 | 作用 |
---|---|
Object readObject() | 从ObjectInputStream中读取对象 |
使用步骤
- 创建一个ObjectInputStream对象,参数传递字节输入流对象
- 使用ObjectInputStream对象的readObject方法,读取保存对象的文件
- 使用close方法释放资源
- 使用读取的对象
package cn.zhuobo.day15.aboutObjectInputStream;
import cn.zhuobo.day15.aboutObjectOutputStream.Person;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Demo01ObjectInputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day15-code/writeObject.txt"));
Object o = ois.readObject();
ois.close();
// System.out.println(o.toString());
Person p = (Person)o;
System.out.println(p);
}
}
要注意的是
反序列化的前期:类必须实现了Serializable接口,其次是存在类对应的class文件
readObject方法已经声明了抛出ClassNotFoundException,因此这个异常也要处理,或者继续声明throws或者try catch
反序列化的时候出现 java.io.InvalidClassException
,是因为每次对象的类每次生成一个class字节码文件的时候都会计算生成一个UID,如果在序列化只有修改了类,那么该类就会生成新的UID,这就会导致与原来的UID不一致,使得序列化失败。解决方法是人为的定义该类的UID为某一个数字,在类的成员变量中加入以下的声明,这就保证类无论类怎么修改,生成的class文件的UID都是一样的。
private static final long serialVersionUID = 23L;
集合的序列化与反序列化
众所周知,集合也是一个对象,是装了对象的对象,因此将集合序列化也是一样的做法:
package cn.zhuobo.day15.aboutInputStreamReader;
import cn.zhuobo.day15.aboutObjectOutputStream.Person;
import java.io.*;
import java.util.ArrayList;
//将集合的对象序列化,存到文件中
public class Demo02Pratise {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ArrayList<Person> personList = new ArrayList<>();
personList.add(new Person("猪八戒", 360));
personList.add(new Person("孙悟空", 550));
personList.add(new Person("紫霞仙子", 350));
personList.add(new Person("太上老君", 1150));
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("day15-code/writeObject.txt"));
oos.writeObject(personList);// 序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("day15-code/writeObject.txt"));
Object o = ois.readObject();// 反序列化
ArrayList<Person> list = (ArrayList<Person>)o;// 强制类型转为ArrayList集合
for (Person person : list) {
System.out.println(person);
}
ois.close();
oos.close();
}
}