加深关于Serializable的理解
我们知道java.io.Serializable接口是将一个对序列化,所实现的效果就是可以将对象保存起来(例如:硬盘、网络等)。今天一道面试题出的很有意思,题目大概如下:
================Parent.java===================
package com.test; import java.io.Serializable; public class Parent { public Parent(){ System.out.print("p"); } }=======================Sub.java===============================
public class Sub extends Parent implements Serializable{ public Sub(){ super(); System.out.print("c"); } }========================Test.java==============================
package com.test; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class Test { public static void main(String[] args) throws Exception { String data = "E:\\test\\IO_0010\\src\\o.dat"; Sub sub = new Sub(); FileOutputStream fos = new FileOutputStream(data); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(sub); oos.close(); fos.close(); FileInputStream fis = new FileInputStream(data); ObjectInputStream ois = new ObjectInputStream(fis); Sub s =(Sub)ois.readObject(); fis.close(); ois.close(); } }
==========================结束================================
然后输出的结果是:
pcp
当时我选的答案是pcpc,当初我是这样理解的(没做过实验时)。
1、当实例化子类的时候,会先去调用父类的构造函数,所以输出的是p。
2、再去调用子类的构造函数,输出c。
3、读取对象的时候,首先取出父类对象的构造函数,这里又输出p。
4、然后去调用子类的构造函数,输出c
但是事实证明,这么想是有些问题的。于是我又写了个例子,做了个测试。
前2步的理解是基本是正确的。
由于Sub实现了Serialiable接口,对所以sub对象被保存到文件中去了,当使用ObjectInputStream.readObject() 去读取对象的时候。sub的构造函数就不再调用了,但是他的父类Parent没有时间任何接口,父类没有被保存。当读取Sub对象就会去重新构造父类。即调用父类的构造方法,所以输出了p,而没有再次调用子类的构造方法。
如果父类也实现的了Serializable接口,那么重新读取对象的时候就不会再去构造父类或者是子类了。默认,子类也会去继承父类实现的接口。