
1. 介绍
演示如何序列化具有不可序列化的超类的子类。
当特定子类的超类不可序列化时,子类必须保存并还原超类的状态。
就是有一个User
类是父类里面有属性name和sex,而且没有实现Serializable
接口。接着有一个Student
类,继承了User
类并且实现了Serializable
接口,然后怎么实现也把父类的属性也一起序列化?
2. 源代码
src/test/jack/io/demo/ser/case3 · Jack魏/JDK1.1源码阅读学习 - 码云 - 开源中国
ReadingMaterial
父类 注意这里没有实现Serializable
接口。
注意这里的无参构造器,必须要有,不然会报错:no valid constructor
因为ObjectInputStream
类里面使用了反射。
import java.io.*;
// 超类不实现可序列化
class ReadingMaterial {
/**
* 我们没有将它们设为私有,因为我们需要子类 Book 才能保存这个超类的状态。
* 或者,我们可以将这些设为私有并创建允许访问 Book 子类的 set 和 get 函数。
* 如果我们没有对私有字段做到这一点,那么字段将无法保存!
*/
protected String author;
protected String subject;
protected int yearwritten;
// 其他相关数据和方法
/*
* 一个强制性的公共无参数构造函数......将用于重建这个不可序列化的类。
*/
public ReadingMaterial() {}
ReadingMaterial(String auth, String sub, int year) {
author = auth;
subject = sub;
yearwritten = year;
}
}
Book
子类,注意这里必须实现Serializable
接口。
获取父类属性的时候如果是private,就需要用到super关键字了,并且父类里面必须要有setter和getter不然访问不到。。
import java.io.*;
class Book extends ReadingMaterial implements Serializable {
int numpages;
String name;
boolean ishardcover;
// 其他相关信息和方法
Book(int pages, String n, boolean hardcover, String author,
String subject, int yearwritten)
{
super(author, subject, yearwritten);
numpages = pages;
name = n;
ishardcover = hardcover;
}
/**
* 通过调用 defaultWriteObject 保存自己的字段,然后显式保存其超类型的字段
*
* @serialData 通过调用 defaultWriteObject 存储自己的可序列化字段并将超类型字段保存为可选数据。
* 可选数据按以下顺序写入; author 字段写为对象,subject 是对象,yearwritten 字段写为整数。
*/
private void writeObject(ObjectOutputStream out) throws IOException {
// 首先通过调用 defaultWriteObject 来处理此类的字段
out.defaultWriteObject();
/*
* 由于超类没有实现 Serializable 接口,我们显式地进行了保存……由于这些字段不是私有的,我们可以直接访问它们。
* 如果它们是私有的,则超类必须实现 get 和 set 方法,这些方法将允许子类进行必要的访问以正确保存。
*/
out.writeObject(author);
out.writeObject(subject);
out.writeInt(yearwritten);
}
/**
* 通过调用 defaultReadObject 恢复其自己的字段,然后显式恢复其超类型的字段。
*/
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
/*
* 首先通过调用 defaultReadObject 来处理此类的字段
*/
in.defaultReadObject();
/*
* 由于超类没有实现 Serializable 接口,我们显式地进行了恢复……因为这些字段不是私有的,我们可以直接访问它们。
* 如果它们是私有的,则超类将必须实现 get 和 set 方法,这些方法将允许子类进行必要的访问以进行正确的保存或恢复。
*/
author = (String) in.readObject();
subject = (String) in.readObject();
yearwritten = in.readInt();
}
/**
* 打印出字段值。对测试很有用。
*/
public String toString() {
return("Name: " + name + "\n" + "Author: " + author + "\n" + "Pages: "
+ numpages + "\n" + "Subject: " + subject + "\n" + "Year: " + yearwritten
+ "\n");
}
}
测试主类
import java.io.*;
/**
* 此示例显示如何序列化其超类不可序列化的子类。
*
* 当特定的超类不可序列化时,子类负责保存其超类的状态(在其 writeObject 中)
*
* 在JDK1.1 & JDK1.2上编译测试
*
* How to run this example:
* Compile this file: javac NonSerialSuperExample.java
* Then run: java NonSerialSuperExample
*
* 这将在序列化前后打印出书籍对象。
*/
public class NonSerialSuperExample {
/**
* 创建一个 book 对象,对其进行序列化、反序列化,然后打印出来以测试序列化是否有效。
*/
public static void main(String args[]) {
// 创建一个 Book 对象
Book bookorg = new Book(100, "How to Serialize", true, "R.R", "Serialization", 1997);
Book booknew = null;
// 序列化 Book
try {
FileOutputStream fo = new FileOutputStream("tmp");
ObjectOutputStream so = new ObjectOutputStream(fo);
so.writeObject(bookorg);
so.flush();
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
// 反序列化 Book
try {
FileInputStream fi = new FileInputStream("tmp");
ObjectInputStream si = new ObjectInputStream(fi);
booknew = (Book) si.readObject();
}catch (Exception e) {
System.out.println(e);
System.exit(1);
}
// 如果我们做的一切都正确,这些书应该是一样的!
System.out.println();
System.out.println("Printing original book...");
System.out.println(bookorg);
System.out.println("Printing new book... ");
System.out.println(booknew);
System.out.println("The original and new should be the same!");
System.out.println();
}
}
3. 运行
编译:
javac NonSerialSuperExample.java
javac Book.java
javac ReadingMaterial.java
运行:
java NonSerialSuperExample

4. 总结
感觉这个还是比较常用的,
如果父类不想实现序列化接口,而且子类又想序列化,
用这种方式还是不错的。
首先掌握这种形式,有需要去看这个实例即可。
网友评论