使用对象流实现序列化
如果需要将某个对象保存到磁盘上或者通过网络传输,那么这个类应该实现 Serializable 接口或者 Externalizable 接口之一。
使用 Serializable 来实现序列化非常简单,主要让目标类实现 Serializable 标记接口即可,无须实现任何方法。
一旦某个类实现了 Serializable 接口,该类的对象就是可序列化的,程序可以通过如下两个步骤来序列化该对象。
序列化
- 创建一个ObjectOutputStream,这个输出流是一个处理流,所以必须建立在其他节点流的基础之上。
- 调用ObjectOutputStream对象的writeObject()方法输出可序列化对象。
定义一个普通的Java类,只是实现了Serializable接口,该接口标识该类的对象是可序列化的。
public class Canine implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public Canine(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class ObjectStreamTest {
public static void main(String[] args) {
try(
FileOutputStream outputStream = new FileOutputStream("src\\com\\rrz\\object.txt");
ObjectOutputStream oOut = new ObjectOutputStream(outputStream);
) {
oOut.writeObject(new Canine("狮子"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行上面程序,将会生成一个 object.txt 文件
打开是乱码的,因为编码解码不一致导致
反序列化
从二进制流中恢复 java 对象
- 创建一个ObjectInputStream输入流,这个输入流是一个处理流,所以必须建立在其他节点流的基础之上。
- 调用ObjectInputStream对象的readObject()方法读取流中的对象,该方法返回一个Object类型的Java对象,如果程序知道该Java对象的类型,则可以将该对象强制类型转换成其真实的类型。
主要看构造器
public class Canine implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
public Canine(String name) {
System.out.println("这是一个有参数的构造器");
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
反序列化
public class ObjectStreamTest {
public static void main(String[] args) {
try(
FileInputStream inputStream = new FileInputStream("src\\com\\rrz\\object.txt");
ObjectInputStream in = new ObjectInputStream(inputStream);
) {
Canine object = (Canine) in.readObject();
System.out.println(object.getName());
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
结果
看到并没有打印“这是一个有参数的构造器”,说明并没有调用构造器
必须指出的是,反序列化读取的仅仅是Java对象的数据,而不是Java类,因此采用反序列化恢复Java对象时,必须提供该Java对象所属类的class文件,否则将会引发ClassNotFoundException异常。
还有一点需要指出:Canine 类只有一个有参数的构造器,没有无参数的构造器,而且该构造器内有一个普通的打印语句。当反序列化读取Java对象时,并没有看到程序调用该构造器,这表明反序列化机制无须通过构造器来初始化Java对象。
提示:
在ObjectInputStream输入流中的readObject()方法声明抛出了ClassNotFoundException异常,也就是说,当反序列化时找不到对应的Java类时将会引发该异常。
如果使用序列化机制向文件中写入了多个Java对象,使用反序列化机制恢复对象时必须按实际写入的顺序读取。
当一个可序列化类有多个父类时(包括直接父类和间接父类),这些父类要么有无参数的构造器,要么也是可序列化的——否则反序列化时将抛出InvalidClassException异常。如果父类是不可序列化的,只是带有无参数的构造器,则该父类中定义的成员变量值不会序列化 到二进制流中。