谈谈J2SE中的序列化(二)

发表于:2007-07-04来源:作者:点击数: 标签:
当序列化遇到继承… 当一个父类实现Serializable接口后,他的子类都将自动的实现序列化。 以下验证了这一点: package Serial; import java.io.Serializable; public class SuperC implements Serializable {//父类实现了序列化 int supervalue; public Super
当序列化遇到继承…

当一个父类实现Serializable接口后,他的子类都将自动的实现序列化。

以下验证了这一点:



package Serial;

import java.io.Serializable;

public class SuperC implements Serializable {//父类实现了序列化

int supervalue;

public SuperC(int supervalue) {

this.supervalue = supervalue;

}

public String toString() {

return "supervalue: "+supervalue;

}

}



public class SubC extends SuperC {//子类

int subvalue;

public SubC(int supervalue,int subvalue) {

super(supervalue);

this.subvalue=subvalue;

}

public String toString() {

return super.toString()+" sub: "+subvalue;

}

}



public class Test1 {

public static void main(String [] args){

SubC subc=new SubC(100,200);

FileInputStream in=null;

FileOutputStream out=null;

ObjectInputStream oin=null;

ObjectOutputStream oout=null;

try {

out = new FileOutputStream("Test1.txt");//子类序列化

oout = new ObjectOutputStream(out);

oout.writeObject(subc);

oout.close();

oout=null;



in = new FileInputStream("Test1.txt");

oin = new ObjectInputStream(in);

SubC subc2=(SubC)oin.readObject();//子类反序列化

System.out.println(subc2);

} catch (Exception ex){

ex.printStackTrace();

} finally{

…此处省略

}

}

}



运行结果如下:

supervalue: 100 sub: 200

可见子类成功的序列化/反序列化了。



怎管让子类实现序列化看起来是一件很简单的事情,但有的时候,往往我们不能够让父类实现Serializable接口,原因是有时候父类是抽象的(这并没有关系),并且父类不能够强制每个子类都拥有序列化的能力。换句话说父类设计的目的仅仅是为了被继承。

要为一个没有实现Serializable接口的父类,编写一个能够序列化的子类是一件很麻烦的事情。java docs中提到:

“To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype''s public, protected, and (if aclearcase/" target="_blank" >ccessible) package fields. The subtype may assume this responsibility only if the class it extends has an accessible no-arg constructor to initialize the class''s state. It is an error to declare a class Serializable if this is not the case. The error will be detected at runtime. ”

也就是说,要为一个没有实现Serializable接口的父类,编写一个能够序列化的子类要做两件事情:

其一,父类要有一个无参的constructor;

其二,子类要负责序列化(反序列化)父类的域。



我们将SuperC的Serializable接口去掉,而给SubC加上Serializable接口。运行后产生错误:

java.lang.Error: Unresolved compilation problem:

Serializable cannot be resolved or is not a valid superinterface

at Serial.SubC.<init>(SubC.java:15)

at Serial.Test1.main(Test1.java:19)

Exception in thread "main"

果真如docs中所说的一样,父类缺少无参构造函数是不行的。



接下来,按照docs中的建议我们改写这个例子:

public abstract class SuperC {

int supervalue;



public SuperC(int supervalue) {

this.supervalue = supervalue;

}



public SuperC(){}//增加一个无参的constructor



public String toString() {

return "supervalue: "+supervalue;

}

}



public class SubC extends SuperC implements Serializable {



int subvalue;



public SubC(int supervalue,int subvalue) {

super(supervalue);

this.subvalue=subvalue;

}



public String toString() {

return super.toString()+" sub: "+subvalue;

}



private void writeObject(java.io.ObjectOutputStream out)

throws IOException{

out.defaultWriteObject();//先序列化对象

out.writeInt(supervalue);//再序列化父类的域

}



private void readObject(java.io.ObjectInputStream in)

throws IOException, ClassNotFoundException{

in.defaultReadObject();//先反序列化对象

supervalue=in.readInt();//再反序列化父类的域

}

}

运行结果证明了这种方法是正确的。在此处我们用到了writeObject/ readObject方法,这对方法如果存在的话,序列化时就会被调用,以代替默认的行为(以后还要探讨,先了解这么多)。我们在序列化时,首先调用了ObjectOutputStream的defaultWriteObject,它使用默认的序列化行为,然后序列化父类的域;反序列化的时候也一样。



归纳一下:

目的
行为

为一个实现Serializable接口的父类,编写一个能够序列化的子类
子类将自动的实现序列化

为一个没有实现Serializable接口的父类,编写一个能够序列化的子类
1, 父类要有一个无参的constructor;

2, 子类要先序列化自身,然后子类要负责序列化父类的域

原文转自:http://www.ltesting.net