美文网首页
Serializable官方实例解析03-序列化具有不可序列化的

Serializable官方实例解析03-序列化具有不可序列化的

作者: Jack魏 | 来源:发表于2022-05-16 21:57 被阅读0次

官方地址:Using Serialization with a Custom Data Format

Java官方实例-Serializable03-序列化具有不可序列化的超类的子类

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
image.png

4. 总结

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

相关文章

网友评论

      本文标题:Serializable官方实例解析03-序列化具有不可序列化的

      本文链接:https://www.haomeiwen.com/subject/jfsqurtx.html