我想询问实现“Serializable”接口的父节点的子节点是否也实现了“Serializable”接口,或者换句话说,该子节点是否可以被序列化?
答案 0 :(得分:17)
我想询问实现“Serializable”接口的父节点的子节点是否也实现了“Serializable”接口,或者换句话说,该子节点是否可以被序列化?
第一部分的答案是肯定的。这是Java继承的自然结果。
第二部分的答案是并非总是如此!
考虑一下:
public class Parent implements Serializable {
private int i;
// ...
}
public class Child extends Parent {
private final Thread t = new Thread(); // a non-serializable object
// ...
}
Parent
的实例可以序列化,但Child
的实例不能......因为它有一个类型(Thread
)不可序列化的属性。
(现在,如果t
被声明为transient
,或者使用默认序列化机制避免Child
,Child
可以序列化。但我的观点是可序列化是紧急财产,而不是可继承财产。)
答案 1 :(得分:8)
是。如果父实现Serializable
,那么任何子类也都是Serializable
。
static class A implements Serializable {
}
static class B extends A {
}
public static void main(String[] args) {
Serializable b = new B(); // <-- this is a legal statement.
}
B
也实现了Serializable
。
答案 2 :(得分:1)
简答:是的,如果父序列化,则子类自动序列化。
长答案:
如果Parent类是Serializable,那么子类默认为Serializable。 JVM检查父类是否实现Serializable,如果是,则将子类视为可序列化。因此,序列化是一个可继承的概念,从父母到孩子。
public class ParentSerializableNotChild {
public static void main(String[] args) throws Exception{
Child chileSerialize = new Child();
//Serialization
FileOutputStream fos = new FileOutputStream("test.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(chileSerialize);
FileInputStream fis = new FileInputStream("test.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Child childDeserialize = (Child) ois.readObject();
System.out.println(childDeserialize.i + "---" + childDeserialize.j); //10---20
}
}
class Parent implements Serializable{
int i = 10;
}
class Child extends Parent{
int j = 20;
}
如果父类不可序列化,那么也可以序列化子类。最好的例子是Object类,Object类不实现Serializable,但任何Object类的子类都可以实现Serializable。
public class ChildSerializedParentNot {
public static void main(String[] args) throws Exception{
Dogy d = new Dogy();
d.i = 888;
d.j = 999;
FileOutputStream fos = new FileOutputStream("inheritance.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
System.out.println("Serializing");
oos.writeObject(d);
FileInputStream fis = new FileInputStream("inheritance.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
System.out.println("Deserializing");
Dogy d2 = (Dogy) ois.readObject();
System.out.println(d2.i + "-----" + d2.j);
}
}
class Animal{
int i = 10;
Animal(){
System.out.println("Parent class cons");
}
}
class Dogy extends Animal implements Serializable{
Dogy(){
System.out.println("Child class constructor");
}
int j = 20;
}
输出:
父母阶层利弊
子类构造函数
序列化
反序列化
父母阶层利弊
10 ----- 999
从上面看,有3例在儿童被序列化而非父母时发生。
案例1:在序列化期间,JVM会检查是否有任何实例变量来自非序列化父类。如果是这样,父类不可序列化并且其实例变量参与序列化,则jvm忽略实例变量的值并将默认值存储在文件中。 (在上面的例子中,i在文件中存储为0)。
案例2:在反序列化期间,JVM检查是否有任何实例变量来自非序列化父类。如果是这样,JVM将运行INSTANCE CONTROL FLOW并恢复对象的原始值。
实例控制流程(简称)http://java2bigdata.blogspot.in/2015/05/instance-control-flow-in-java.html:
1.实例成员的识别。
2.执行实例变量赋值&amp;实例。
3.执行构造函数。
情况3:由于在实例控制流中,执行构造函数。因此,在Non serialized parent的情况下,调用no-arg构造函数,该构造函数可以是用户提供的或jvm创建的。如果没有no-arg构造函数,那么它将导致InvalidClassException。
答案 3 :(得分:1)
我们不需要一个no-arg构造函数,而父类是可序列化的。
但是当子序列化而不是父级时,我们必须在父级中使用no-arg const来在反序列化时根据需要设置值,否则我们将具有默认值。
答案 4 :(得分:0)
如果Parent类具有Serializable行为,那么默认情况下,所有子类都具有Serializable行为。
class Parent implements Serializable{
int x;
}
class Children extends Parent{
int m;
public static void main(String args[]){
Children c = new Children();
c.m =10;
c.x =20;
// Enter Serialization Code;
// Enter De serialization Code;
}
}
注意:读取反序列化对象时,您将能够检索序列化状态。