首页 > 代码库 > Java 之 I/O 系列 02 ——序列化(二)

Java 之 I/O 系列 02 ——序列化(二)

Java 之 I/O 系列 目录

Java 之 I/O 系列 01 ——基础

Java 之 I/O 系列 02 ——序列化(一) 

Java 之 I/O 系列 02 ——序列化(二)

 继续上篇的第二个问题

如果一个类实现了Serializable接口,但是它的父类没有实现 ,这个类可不可以序列化?

Object是每个类的超类,但是它没有实现 Serializable接口,但是我们照样在序列化对象,所以说明一个类要序列化,它的父类不一定要实现Serializable接口。但是在父类中定义 的状态能被正确 的保存以及读取吗?

还是围绕上面用过的那些类来做一些修改,看下面这个例子。

Book.java这个类和上次的一样,不实现Serializable接口

 

 1 public class Book { 2  3     private int isbn; 4     public Book(int isbn){ 5         this.isbn = isbn; 6     } 7     public int getIsbn() { 8         return isbn; 9     }10     public void setIsbn(int isbn) {11         this.isbn = isbn;12     }13     14     public String toString(){15         return "Book [isbn = "+isbn+"]";16     }17     18 }

 

这里新定义一个类NewBook继承Book类,并且实现 Serializable接口,下面看定义

 1 ublic class NewBook extends Book implements Serializable { 2  3     private String author; 4  5     public NewBook(int isbn, String author) { 6         super(isbn); 7         this.author = author; 8     } 9 10     public String getAuthor() {11         return author;12     }13 14     public void setAuthor(String author) {15         this.author = author;16     }17 18     @Override19     public String toString() {20         return "NewBook [author=" + author + super.toString() + "]";21     }22 }

 

然后,把Student类中Book类型的实例变量修改成NewBook类型,修改后的Student类

 1 public class Student implements Serializable { 2  3     private NewBook book; 4     private String name; 5  6     public Student(NewBook book, String name) { 7         super(); 8         this.book = book; 9         this.name = name;10 11     }12     13     public NewBook getBook() {14         return book;15     }16 17 18     public void setBook(NewBook book) {19         this.book = book;20     }21 22 23     public String getName() {24         return name;25     }26 27 28     public void setName(String name) {29         this.name = name;30     }31 32 33     public String toString() {34         return "Student [book=" + book + ", name=" + name + "]";35     }36     37 38 }

 

Simulator类的内容不变

 1 public class Simulator { 2     public static void main(String[] args) { 3         new Simulator().go(); 4     } 5  6     private void go() { 7         Student student = new Student(new NewBook(2014,"author11"), "xingle"); 8         try { 9             ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("test"));10             out.writeObject(student);11             //System.out.println(System.currentTimeMillis());12             System.out.println("object has been written  ");13             out.close();14         } catch (FileNotFoundException e) {15             e.printStackTrace();16         } catch (IOException e) {17             e.printStackTrace();18         }19         20         try {21             ObjectInputStream in = new ObjectInputStream(new FileInputStream("test"));22             Student stuRead = (Student) in.readObject();23             System.out.println("object read here");24             System.out.println(stuRead);25         } catch (FileNotFoundException e) {26             e.printStackTrace();27         } catch (IOException e) {28             e.printStackTrace();29         } catch (ClassNotFoundException e) {30             e.printStackTrace();31         }32 33     }34 35 }

 

运行这个程序 ,看下输出结果:

 

从结果可以看出,对象写成功了,但在读取的过程中出现了问题,具体的异常原因:no validconstructor,即没有有效的构造函数,那么 到底 是哪个 类没有有效的构造函数呢,到底需要一个什么样的构造函数呢?

对于这种情况 ,即父类没有实现Serializable接口时,但其子类实现 了此接口,那么 这个子类是可以序列化的,但是在反序列化的过程 中会调用 父类 的无参构造函数,上面异常抛出的原因就是因为我们在Book类中没有一个无参的构造函数。好,那我们下面就为Book类添加一个默认的构造函数。

 1 public class Book { 2  3     private int isbn; 4     //增加默认构造函数 5     public Book(){ 6         isbn = 100; 7         System.out.println("Book class no-arg constructor invoked.."); 8     } 9     public Book(int isbn){10         this.isbn = isbn;11     }12     public int getIsbn() {13         return isbn;14     }15     public void setIsbn(int isbn) {16         this.isbn = isbn;17     }18     19     public String toString(){20         return "Book [isbn = "+isbn+"]";21     }22     23 }

 

再来执行一次程序 ,看输出结果如何:

 可以看到在反序列化的过程中调用了Book类的无参构造执行一个初始化的操作。

 

 总结一下 :如果父类没有实现Serializable接口,但其子类实现 了此接口,那么 这个子类是可以序列化的,但是在反序列化的过程 中会调用 父类 的无参构造函数,所以在其直接父类(注意是直接父类)中必须有一个无参的构造函数。

 

对于第2个问题的讨论就到这里,接下来我们提出第3个问题:

如果将一个对象写入某文件(比如是a),那么之后对这个对象进行一些修改,然后把修改的对象再写入文件a,那么文件a中会包含该对象的两个版本吗?

修改Simulator类如下: