Java 何时调用ReadObjectNodeData

Java 何时调用ReadObjectNodeData,java,serialization,Java,Serialization,我正在阅读有效的Java项目74。我对java对象的序列化很感兴趣。但有一种方法“readObjectNoData”让我感到困惑 下面是对JavaDoc的解释 对于可序列化对象,ReadObjectNodeData方法允许类在子类实例被反序列化且序列化流未将相关类列为反序列化对象的超类的情况下控制其自身字段的初始化。当接收方使用与发送方不同的反序列化实例类版本,并且接收方版本扩展了未由发送方版本扩展的类时,可能会发生这种情况。如果序列化流被篡改,也可能发生这种情况;因此,ReadObjectNo

我正在阅读有效的Java项目74。我对java对象的序列化很感兴趣。但有一种方法“readObjectNoData”让我感到困惑

下面是对JavaDoc的解释

对于可序列化对象,ReadObjectNodeData方法允许类在子类实例被反序列化且序列化流未将相关类列为反序列化对象的超类的情况下控制其自身字段的初始化。当接收方使用与发送方不同的反序列化实例类版本,并且接收方版本扩展了未由发送方版本扩展的类时,可能会发生这种情况。如果序列化流被篡改,也可能发生这种情况;因此,ReadObjectNodeData对于正确初始化反序列化对象非常有用,尽管源流“恶意”或不完整

它说,当我序列化一个对象时,它是旧版本,不扩展父类,但当我反序列化时,该类升级到新版本并扩展其他一些类

我真的很想玩这个。所以我有一个雇员类

public class Employee implements Serializable { //v1
  public String name;
  public int age;
  protected String address;
  static final long serialVersionUID = 1L;

  public Employee()
  {
    name= "John";
    age = 1;
    address ="N/A";
  }

  public Employee(String name , int age, String address)
  {
    this.name = name;
    this.age = age;
    this.address = address;
  }
}
public class Employee extends Person { //v2
  protected String address ;
  static final long serialVersionUID = 1L;
  public Employee()
  {
    super();
    address ="N/A";
  }

  public Employee(String name , int age, String address)
  {
    super(name,age);
    this.address = address;
  }
  private void readObjectNoData() throws ObjectStreamException {
      name = "John";
      age = 1;
  }
}
和一个序列化类

public class Se {
    public static void main(String [] args) {
        Employee e = new Employee();

        try {
            FileOutputStream fileOut =
                new FileOutputStream("tmp.txt");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(e);
            out.close();
            fileOut.close();
            System.out.printf("Serialized data is saved in tmp.txt");
        }catch(IOException i) {
            i.printStackTrace();
        }
    }
}
将Employee对象序列化为tmp.txt后,我更改Employee类

public class Employee implements Serializable { //v1
  public String name;
  public int age;
  protected String address;
  static final long serialVersionUID = 1L;

  public Employee()
  {
    name= "John";
    age = 1;
    address ="N/A";
  }

  public Employee(String name , int age, String address)
  {
    this.name = name;
    this.age = age;
    this.address = address;
  }
}
public class Employee extends Person { //v2
  protected String address ;
  static final long serialVersionUID = 1L;
  public Employee()
  {
    super();
    address ="N/A";
  }

  public Employee(String name , int age, String address)
  {
    super(name,age);
    this.address = address;
  }
  private void readObjectNoData() throws ObjectStreamException {
      name = "John";
      age = 1;
  }
}
这是我的个人课

class Person implements Serializable{
  protected String name;
  protected int age;

  Person() {
    this("John",1);
  }
  Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
}
当我被反序列化的类反序列化时

public class De {
  public static void main(String [] args) {
    Employee e = null;
    try {
      FileInputStream fileIn = new FileInputStream("tmp.txt");
      ObjectInputStream in = new ObjectInputStream(fileIn);
      e = (Employee) in.readObject();
      in.close();
      fileIn.close();
    }catch(IOException i) {
      i.printStackTrace();
      System.out.println("IOException");
      return;
    }catch(ClassNotFoundException c) {
      System.out.println("Employee class not found");
      c.printStackTrace();
      return;
    }

    System.out.println("Deserialized Employee...");
    System.out.println("Name: " + e.name);
    System.out.println("Address: " + e.address);
    System.out.println("Age: " + e.age);
  }
}
输出总是显示

Deserialized Employee...
Name: null
Address: N/A
Age: 0
即使我在ReadObjectNodeData方法中设置调试点,它也不会被触发,我无法在线找到任何可运行的示例,所以我在这里提供了很多代码。有人知道我错过了什么吗


任何评论都将不胜感激。

这是一种独特的情况,类的反序列化程序具有基于子类(Person)的类(Employee)版本

子类可以说“如果我的基类在序列化数据中是而不是,那就好了——只需创建一个空的基类即可

编辑如下

尝试这两个版本的“反序列化”。我的意思是序列化您的v1员工,然后尝试以下操作:

import java.io.Serializable;
public class Employee extends Person implements Serializable { //v2
  protected String address ;
  static final long serialVersionUID = 1L;

  public Employee()
  {
    super();
    address ="N/A";
  }

  public Employee(String name , int age, String address)
  {
    super(name,age);
    this.address = address;
  }

}

你会看到一个例外

Exception in thread "main" java.lang.IllegalArgumentException
    at test.serialization.Person.readObjectNoData(Person.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at java.io.ObjectStreamClass.invokeReadObjectNoData(ObjectStreamClass.java:1089)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1955)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1808)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1353)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:373)
    at test.serialization.De.main(De.java:22)

希望这对您有所帮助

谢谢您的回复。但是如果我将ReadObjectNodeData方法的内容更改为name=“Bo"; 年龄=50岁;反序列化还将显示John,N/A,1,这意味着未触发ReadObjectNodeData。在什么情况下会触发该函数?编辑答案以显示完整的堆栈跟踪。供您参考。谢谢您的帮助。因此ReadObjectNodeData应该在超类中写入,并且超类应该实现序列化。使用类加载器,可以在一次运行中完成所有测试吗?