在序列化和反序列化期间如何调用构造函数?

时间:2011-11-15 18:46:00

标签: java serialization

在序列化和反序列化期间如何调用构造函数

  1. 当有一个类实现serializable?
  2. 当有父/子关系且只有子实现可序列化时?
  3. 当有父/子关系且父和子都实现可序列化时?

6 个答案:

答案 0 :(得分:43)

在反序列化期间,将为继承层次结构中未实现Serializable的第一个类调用可访问的默认构造函数。

> A Serializable class must have access to the no-arg constructor of its first nonserializable superclass

答案 1 :(得分:30)

示例:

public class ParentDeserializationTest {

public static void main(String[] args){
    try {
        System.out.println("Creating...");
        Child c = new Child(1);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        c.field = 10;
        System.out.println("Serializing...");
        oos.writeObject(c);
        oos.flush();
        baos.flush();
        oos.close();
        baos.close();
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        System.out.println("Deserializing...");
        Child c1 = (Child)ois.readObject();
        System.out.println("c1.i="+c1.getI());
        System.out.println("c1.field="+c1.getField());
    } catch (IOException ex){
        ex.printStackTrace();
    } catch (ClassNotFoundException ex){
        ex.printStackTrace();
    }
}

public static class Parent {
    protected int field;
    protected Parent(){
        field = 5;
        System.out.println("Parent::Constructor");
    }
    public int getField() {
        return field;
    }
}

public static class Child extends Parent implements Serializable{
    protected int i;
    public Child(int i){
        this.i = i;
        System.out.println("Child::Constructor");
    }
    public int getI() {
        return i;
    }
}

}

输出:

Creating...
Parent::Constructor
Child::Constructor
Serializing...
Deserializing...
Parent::Constructor
c1.i=1
c1.field=5

因此,如果对序列进行反序列化,则不会调用其构造函数,但会调用其父级的默认构造函数。 并且不要忘记:所有可序列化对象都应该有一个没有参数的标准构造函数。

答案 2 :(得分:6)

  1. 如果我们必须精确,就没有“一类”这样的东西。 Java中的每个对象都扩展了Object类,无论是作为其层次结构的直接超类还是间接根。因此,没有构造函数可以运行,但假装是这种情况,那么我们不会重新创建某个对象,我们只是创建一个新对象。

  2. 当存在父/子关系时,它取决于父级是否为Serialiable。如果父级不可序列化,超级构造函数将运行!如果父级和子级都是可序列化的,则不会调用构造函数。

  3. 更多信息?

    http://www.java-questions.com/Serialization_interview_questions.html

答案 3 :(得分:6)

  

在序列化和反序列化期间如何调用构造函数

     
      
  1. 当有一个类实现serializable时?

  2.   
  3. 当有父/子关系且只有子实现可序列化时?

  4.   
  5. 当有父/子关系并且父和子都实现可序列化时?

  6.   

在我看来,你的问题的答案是:

1)如果一个类正在实现serializable,那么只有那个类没有父类。 构造函数流就像默认构造函数一样,将调用未实现可序列化的父类。在这种情况下,它是Object类。所以Object类的No-arg构造函数将运行并将创建虚拟对象,而调用readObject()字段将由反射和数据设置,并保存在内存或文件中。

2)如果只有子实现可序列化,则流将进入直到不可序列化的基类。如果不正确的基类没有被序列化那么(该类应该有NO-Arg构造函数)在这种情况下,NO-Arg构造函数将为基类运行。

3)如果序列化了所有父项,那么flow将转到Object类,No-Arg构造函数将运行Object类。

注意:但是你可以通过实现externalizable接口来序列化,然后默认构造函数(NO-ARG)将在反序列化过程中调用该类,而不是父类。

答案 4 :(得分:6)

首先在反序列化时没有任何construtor调用,所有字段的值都将通过反射来设置。

如果将类标记为Serializable而不是JVM,则在反序列化时通过反射设置字段的值,然后JVM查找它的超类,如果没有标记为Serializable,则默认构造函数将调用然后调用next super等等。

看看这个场景:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Test {

    public static void main(String...strings) throws IOException, ClassNotFoundException {
        Employee emp = new Employee();
        emp.companyName = "XYZ";
        emp.employeeName = "ABC";

        getSirielization(emp);
        Employee em = (Employee) getDeSirielization();
        System.out.println(em.companyName+" "+em.employeeName);

    }

    public static void getSirielization(Object object) throws IOException {

        File f = new File("/home/server/ironman/serializedFile.txt");
        FileOutputStream fo = new FileOutputStream(f);
        ObjectOutputStream oob = new ObjectOutputStream(fo);
        oob.writeObject(object);
    }

    public static Object getDeSirielization() throws IOException, ClassNotFoundException {

        File f = new File("/home/server/ironman/serializedFile.txt");
        FileInputStream fo = new FileInputStream(f);
        ObjectInputStream oob = new ObjectInputStream(fo);
        Object object = oob.readObject();
        return object;
    }
}

class Company {
    String companyName;

    public Company() {
        System.out.println("Company-Default");
    }

}

class Employee extends Company implements Serializable {

    private static final long serialVersionUID = -3830853389460498676L;

    String employeeName;

    public Employee() {

        System.out.println("hello2");
    }
}

答案 5 :(得分:0)

反序列化过程不使用对象的构造函数 - 在没有构造函数的情况下实例化对象,并使用序列化实例数据进行初始化。对于实现Serializable的类,构造函数的唯一要求是其继承层次结构中的第一个非可序列化超类必须具有无参数构造函数。