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

How are constructors called during serialization and deserialization?

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

  • 当有一个类实现可序列化时?
  • 当存在父/子关系并且只有子级实现可序列化时?
  • 当存在父子关系并且父子都实现可序列化时?

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

    >可序列化的类必须有权访问其第一个不可序列化的超类的no-arg构造函数


    例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
     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;
            }
        }
    }

    输出:

    1
    2
    3
    4
    5
    6
    7
    8
    Creating...
    Parent::Constructor
    Child::Constructor
    Serializing...
    Deserializing...
    Parent::Constructor
    c1.i=1
    c1.field=5

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


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

    如果您将类标记为Serializable而不是JVM,则在反序列化时通过反射设置字段的值,然后JVM查找其超类,并且如果该类未标记为Serializable,则将调用默认构造函数,然后调用下一个超类,依此类推。上。

    看一下这种情况:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    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");
        }
    }


    How are the constructors called during serialization and deserialization

  • When there is one class implementing serializable?

  • When there is parent/child relationship and only child implements serializable?

  • When there is parent/child relationship and both parent and child implements serializable?

  • 我认为您的问题的答案是:

    1)如果一个类正在实现可序列化,并且仅该类不存在父类。
    构造函数流程就像默认构造函数将调用未实现可序列化的父类。在这种情况下,它是Object类。因此Object类的No-arg构造函数将运行并创建伪对象,并且在调用readObject()字段时将通过反射和保存在内存或文件中的数据进行设置。

    2)如果只有孩子实现了可序列化,那么流程将一直进行到不可序列化的基类。如果dierect基类未序列化,则(该类应具有NO-Arg构造函数)在这种情况下,NO-Arg构造函数将为基类运行。

    3)如果所有父级都已序列化,则流程将转到Object类,而No-Arg构造函数将运行Object类。

    注意:但是,您可以通过实现外部化接口进行序列化,然后在反序列化过程中,将仅对该类调用默认构造函数(NO-ARG),而不会对其父类进行调用。


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

  • 当存在父/子关系时,取决于父/母是否可序列化。如果父级不可序列化,则超级构造函数将运行!如果父级和子级都可序列化,则不会调用任何构造函数。

  • 更多信息?

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


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