问题描述
我对使用新的 JDK 16 记录很感兴趣,但是当我尝试创建一个具有附加参数的新记录时,出现错误:
public record DrivePacket(Path drivePath,long driveSize) {
public DrivePacket(Path drivePath,long driveSize) {
this.drivePath = drivePath;
this.driveSize = driveSize;
}
public DrivePacket(Path drivePath,long driveSize,String ID) {
this(drivePath,driveSize);
this.id = id;
}
}
记录仅用于没有任何可变性的对象,还是可以随着时间的推移而扩展?
我对此类类有一个新要求(特别是意外添加了通过 NFS 共享的驱动器类型“远程”驱动器。
我发现自己试图想出一些方案,例如使用 driveSize
来指示“远程”状态,但这正是开发枚举的原因。
这种情况我该怎么办?我可以向构造函数添加选项并将它们存储在私有 final 字段中吗?或者我应该创建一个 DrivePacket
-> RemoteDrivePacket
的子类,还是我应该为 RemoteDrivePacket
创建一个标记接口?
开发人员打算使用它的典型方式是什么?
解决方法
它们不能被子类化,也不能有“单独添加”意义上的字段,但你可以简单地在那里扔一个新属性; public record DrivePacket(Path drivePath,long driveSize,String id) {}
工作正常。
当然,现在所有创建新 DrivePacket 对象的代码都需要更新。您应该能够添加一个自定义构造函数,例如填充一些默认值。
如果您希望它们可构建、可扩展、具有非最终字段等,请查看 lombok's @Value。 (免责声明:我确实在 lombok 上工作)。
--编辑--
我想我会在此处添加该构造函数,以展示如何确保调用 new DrivePacket(path,size)
(无 ID)的“旧”代码能够正常工作:
public record DrivePacket(Path drivePath,String id) {
public DrivePacket(Path drivePath,long driveSize) {
this(drivePath,driveSize,"");
}
}
'full' all-3-of-em 构造函数也存在,这定义了第二个构造函数,确保任何只执行 new DrivePacket(path,size)
的代码获得 {{1} 的 ID }}。所有 DrivePacket 都有一个 ID(你不能让一半有它而另一半没有;那么“DrivePacket”将不再描述单一类型概念,而不是 java 的工作原理),现在旧式 DrivePacket 对象有一个ID 的空字符串。
可以兼容添加一个组件到记录中,如果有一个合理的默认值,这是在设计这个特性时考虑的。考虑:
record Point(int x,int y) { }
并且您想添加一个 z
组件,其中零是合理的默认值。如果你只是一味地改成
record Point(int x,int y,int z) { }
这不会与现有客户端的源代码或二进制文件兼容,但您可以通过为旧状态描述提供替代构造函数来解决此问题:
record Point(int x,int z) {
public Point(int x,int y) { this(x,y,0); }
}
现在,旧的构造函数调用(二进制和源代码)和旧的序列化实例(如果默认值是相同的零默认值,序列化将用于序列化流中不存在的字段)将按预期工作。但是,它与rename、reorder 或remove 组件不兼容。