jf_*_*jf_ 3 java serialization java-record java-16
在这篇关于可序列化记录的文章中指出
反序列化通过调用记录类的规范构造函数来创建新的记录对象,将从流中反序列化的值作为参数传递给规范构造函数。这是安全的,因为这意味着记录类可以在将值分配给字段之前对其进行验证,就像普通 Java 程序通过 new 创建记录对象一样。“不可能”的对象是不可能的。
这与仅用于验证的构造函数争论。然而,当构造函数操作参数时,这会导致相当奇怪的行为。考虑这个非常人为的简单示例:
以下记录a在保存之前进行操作:
import java.io.Serializable;
public record TRecord (int a) implements Serializable {
public TRecord {
a = a-1;
}
}
Run Code Online (Sandbox Code Playgroud)
下面的程序只是在第一次保存序列化记录并在随后的时间加载它:
import java.io.*;
public class TestRecords {
public static void main(String args[]) {
TRecord a1 = null;
try {
FileInputStream fileIn = new FileInputStream("tmp");
ObjectInputStream in = new ObjectInputStream(fileIn);
a1 = (TRecord) in.readObject();
in.close();
fileIn.close();
} catch (IOException | ClassNotFoundException i) {
// ignore for now
}
if (a1 == null) {
try {
a1 = new TRecord(5);
FileOutputStream fileOut = new FileOutputStream("tmp");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(a1);
out.close();
fileOut.close();
System.out.printf("Serialized data is saved in /tmp/employee.ser");
} catch (IOException i) {
i.printStackTrace();
}
}
System.out.println(a1);
}
}
Run Code Online (Sandbox Code Playgroud)
第一次运行的输出是TRecord[a=4],并且TRecord[a=3]在后续运行中,因此我从反序列化中获得的状态与我在那里输入的状态不同。使用如下类似的类,TClass[a=4]每次都会得到相同的结果。
import java.io.Serializable;
public class TClass implements Serializable {
private int a;
public TClass(final int a) {
this.a = a-1;
}
public int getA() {return a;}
public String toString() {
return "Class[" + a + "]";
}
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是:是否有任何规则禁止/不鼓励将构造函数用于验证以外的任何内容(例如,我正在考虑在存储输入之前对密码进行哈希处理)?或者是否有另一种方法来反序列化对象以便恢复初始状态?
Jor*_*nee 11
如果您查看记录文档,它会显示以下内容:
对于所有记录类,以下不变量必须成立:如果记录 R 的组件是 c1、c2、... cn,那么如果记录实例被复制如下:
Run Code Online (Sandbox Code Playgroud)R copy = new R(r.c1(), r.c2(), ..., r.cn());那么一定是 r.equals(copy) 的情况。
但是,您的记录类不是这种情况:
jshell> TRecord r1 = new TRecord(42);
r1 ==> TRecord[a=41]
jshell> TRecord copy = new TRecord(r1.a());
copy ==> TRecord[a=40]
jshell> r1.equals(copy)
$4 ==> false
Run Code Online (Sandbox Code Playgroud)
换句话说,你的记录类型违反了这个不变性,这也是你看到不一致反序列化的原因。