Java JDK 16记录、构造函数和随时间增加的内容?

Java JDK 16记录、构造函数和随时间增加的内容?,java,java-16,Java,Java 16,我对使用新的JDK 16记录很感兴趣,但是当我尝试创建一个具有附加参数的新记录时,我得到一个错误: public record DrivePacket(Path drivePath, long driveSize) { public DrivePacket(Path drivePath, long driveSize) { this.drivePath = drivePath; this.driveSize = driveSize;

我对使用新的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共享上的驱动器类型remote drive

我发现自己试图提出一些方案,比如使用driveSize来表示远程状态,但实际上这就是开发enum的原因

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


开发人员希望使用的典型方式是什么?

它们不能被子类化,也不能有“单独添加一个”的字段,但您可以简单地在其中添加一个新属性;公共记录DrivePacketPath drivePath、long driveSize、字符串id{}工作正常

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

如果您希望它们是可构建的、可扩展的、具有非最终字段等,请查看。免责声明:我在龙目山工作

-编辑-

我想我应该在这里添加该构造函数,以展示如何确保调用新DrivePacketpath的“旧”代码(大小没有id)能够正常工作:

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

“full”all-3-of-em构造器也存在,这定义了第二个构造器,确保任何刚进入新DrivePacketpath、size的代码都获得ID。所有的驱动器包都有一个ID,你不能让一半的驱动器包有ID,而另一半没有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 y, int z) { 
    public Point(int x, int y) { this(x, y, 0); }
}

现在,如果默认值与序列化用于序列化流中不存在的字段的默认值相同,则旧构造函数调用二进制、源和旧序列化实例。但是,它与重命名、重新排序或删除组件不兼容。

您已将该记录定义为具有两个属性drivePath和driveSize,因此无法将任意属性添加到该记录中。记录类不能被子类化;它们是隐含的最终结果。它们可以扩展,但您试图在错误的级别上进行扩展。记录是为特定目的而设计的。在您的例子中,如果您将记录定义为有一个ID,并且有一个称为规范型ctor的ctor w/a dummy ID或其他任何类型的ctor,就可以了。您也可以使用静态工厂,尽管这里似乎没有必要。我在这里没有看到真正的失败点或设计疏忽;它们被明确设计为轻量级数据载体类。如果您的应用程序需要更广泛的类功能。。。例如子类化,这样设计的这一方面就可以在不重新编码的情况下发展。。。使用常规课程。是-您确实需要在早期做出正确的决策,以预测未来的需求。但这适用于所有方面。阅读以了解有关记录的所有信息、它们发明的原因以及特性和限制。我还想补充一点,即使使用常规类,这也不会像示例中所示的那样进行,在示例中,任意成员属性(非常规命名的ID)试图设置时,您通常会添加一个成员属性,就像对记录所做的一样。通过声明另一个构造函数并忽略现在已删除的参数,您不能安全地删除组件吗?公共点int x,int y,int z{thisx,y;}@MattLeidholm也可能存在调用已删除组件的访问器的现有客户端;您还需要使用显式访问器来伪装这些家伙,该访问器总是返回旧规则下的有效默认值。但即便如此,风险也更大。