0

我对使用新的 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来表示“远程”状态,但实际上这就是开发枚举的原因。

在这种情况下我该怎么办?我可以向构造函数添加选项并将它们存储在私有最终字段中吗?或者我应该创建一个DrivePacket->的子类RemoteDrivePacket,还是应该为它创建一个标记接口RemoteDrivePacket

开发人员打算使用的典型方式是什么?

4

2 回答 2

7

如果存在合理的默认值,则可以将组件兼容地添加到记录中,并且在设计此功能时考虑了这一点。考虑:

record Point(int x, int y) { }

并且您想添加一个z组件,其中零是合理的默认值。如果你只是一味地改成

record Point(int x, int y, int z) { }

这与现有客户端不兼容源代码或二进制文件,但您可以通过为旧状态描述提供替代构造函数来解决此问题:

record Point(int x, int y, int z) { 
    public Point(int x, int y) { this(x, y, 0); }
}

现在,旧的构造函数调用(二进制和源)和旧的序列化实例(如果默认值与序列化将用于序列化流中不存在的字段的零默认值相同)将按预期工作。但是,它不兼容renamereorder删除组件。

于 2021-06-04T21:15:57.143 回答
6

它们不能被子类化,并且它们不能具有“单独添加一个”意义上的字段,但是您可以简单地在其中扔一个新属性;public record DrivePacket(Path drivePath, long driveSize, String id) {}工作正常。

当然,现在所有创建新 DrivePacket 对象的代码都需要更新。您应该能够添加一个自定义构造函数,例如填充一些默认值。

如果您希望它们可构建、可扩展、具有非最终字段等,请查看lombok 的 @Value。(免责声明:我确实在龙目岛工作)。

- 编辑 -

我想我会在此处添加该构造函数,以展示如何确保调用new DrivePacket(path, size)(无 id)的“旧”代码可以正常工作:

public record DrivePacket(Path drivePath, long driveSize, String id) {
    public DrivePacket(Path drivePath, long driveSize) {
        this(drivePath, driveSize, "");
    }
}

'full' all-3-of-em 构造函数存在,它定义了第二个构造函数,确保任何刚刚运行的代码都new DrivePacket(path, size)获得"". 所有 DrivePackets 都有一个 ID(你不能让一半拥有它而另一半没有;那么“DrivePacket”将不再描述单一类型的概念,而不是 java 的工作方式),现在旧式 DrivePacket 对象有一个ID 的空字符串。

于 2021-06-04T01:50:33.543 回答