为什么在反序列化期间未调用/调用默认构造函数

时间:2019-04-18 07:30:04

标签: java

为什么在反序列化机制期间未调用/调用默认构造函数?

按照讨论和评论进行操作,但未找到满意的答案。

我了解反序列化过程中的情况

它通过调用其默认构造函数来创建Object类的实例,并在创建的实例的帮助下,使用ReflectionFactory类的newConstructorForSerialization()方法创建Parent和Child类的实例,该方法在内部创建实例而无需调用类的构造函数。 / p>

以这种方式实施的原因是什么?

vswhere
 public class EmployeeAddress/* implements Serializable */{

/**
 * 
 */
/*private static final long serialVersionUID = 4455988544392627515L;*/
protected String address;

public EmployeeAddress() {
    System.out.println(this.address);
    System.out.println("EmployeeAddress constructor has invoked with no-args");
}

public EmployeeAddress(String address) {
    this.address = address;
    System.out.println(this.address);
    System.out.println("EmployeeAddress constructor has invoked with args");
}

// setter / getter
}

public class Employee extends EmployeeAddress implements Serializable{
/**
 * 
 */
/*public static final long serialVersionUID = 151736201136818635L;*/
private static final long serialVersionUID = 2L;

private String name;
private int age;
private String designation;
private double salary;
private PermanentEmployee pEmpoyee;

private transient long empId;

/*public Employee(String address) {super(address);}*/

public Employee(String name, int age, PermanentEmployee pEmpoyee, String designation, String address, long empId) {
    super(address);
    this.name = name;
    this.age = age;
    this.pEmpoyee = pEmpoyee;
    this.designation = designation;
    this.salary = 2000.00 + pEmpoyee.getBonus();
    this.empId = empId;
}

// setter / getter
}


public class PermanentEmployee implements Serializable{
/**
 * 
 */
private static final long serialVersionUID = -6153718980149785271L;

private double bonus;

public PermanentEmployee() {}

public PermanentEmployee(double bonus) {
    this.bonus = bonus;
}

// setter / getter
}


public class SerializationDemo {
public static void main(String[] args) {

    PermanentEmployee pEmpoyee = new PermanentEmployee(1000.00);

    com.serialization.first.Employee emp = new com.serialization.first.Employee("XYY", 30, pEmpoyee, "Leader", "Nagpur", 2001);
    WriterAndReader.write(emp, "emp.ser");

    System.out.println("Serailization processed..for com.serialization.first.Employee ");


    com.serialization.first.Employee emp1  = (com.serialization.first.Employee) WriterAndReader.read("emp.ser");

    System.out.println("Name: "+ emp1.getName() 
    + ", Age: "+ emp1.getAge() 
    + ", Designation: "+ emp1.getDesignation()
    + ", Salary: " + emp1.getSalary()
    + ", Address: " + emp1.getAddress()
    + ", EmpId: " + emp1.getEmpId());

    System.out.println("Deserailization processed.. for com.serialization.first.Employee ");
}
}

2 个答案:

答案 0 :(得分:1)

因为这是序列化的工作方式。如约书亚·布洛赫(Joshua Bloch)在“有效的Java”中所述:https://qtips.github.io/2017/08/effective-java-chapter-11

有一种机制可以用readObjectreadResolve方法作为构造函数调用的“替换”。在那里,您可以处理流损坏/操作,保护类不变式并恢复不可序列化字段的状态:Java serialization: readObject() vs. readResolve()

出于背后的原因,我很快想到的是,并非所有类都声明一个无参数构造函数。因此,您不能依靠它来创建任何类型的对象。

答案 1 :(得分:1)

  

为什么在反序列化期间未调用/调用默认构造函数   机制?

序列化的对象只是对象被序列化之前在内存中的字节码。因此,当对象反序列化时,它是完全相同的对象。它似乎已创建,并且已为其分配内存。这不是对象的实际创建。因此不会调用构造函数。

考虑此类的输出:

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 Serialization {
    public static void main(String args[]) throws IOException, ClassNotFoundException {
        SomeClass sc = new  SomeClass(2,"sdkjvb"); 
        FileOutputStream fos = new FileOutputStream("serialization.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(sc);
        oos.close();


        FileInputStream fis = new FileInputStream("serialization.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        SomeClass sc1 = (SomeClass) ois.readObject();
        sc1.setS("xjdhj");
        ois.close();
        System.out.println(sc);
        System.out.println(sc1);
    }
}

class SomeClass implements Serializable{

    private static final long serialVersionUID = 1L;
    private int x;
    private String s;
    public SomeClass(int x, String s) {
        super();
        this.x = x;
        this.s = s;
    }
    public void setS(String s) {
        this.s = s;
    }
    @Override
    public String toString() {
        return s+"--->"+x;
    }
}

这是.ser文件的内容:

  

aced 0005 7372 0019 4f62 6a65 6374 4f75 7453 7472 6561 6d2e 536f 6d65   436c 6173 7300 0000 0000 0000 0102 0002 4900 0178 4c00 0173 7400 124c   6a61 7661 2f6c 616e 672f 5374 7269 6e67 3b78 7000 0000 0274 0006 7364   6b6a 7662

这是输出:

sdkjvb--->2
xjdhj--->2

通过调用构造函数只能创建一个对象。另一个只是使用前一个的字节码进行复制。