Java 为什么不使用自定义构造函数推断变量arity记录组件?

Java 为什么不使用自定义构造函数推断变量arity记录组件?,java,arity,java-record,java-16,Java,Arity,Java Record,Java 16,尝试使用录制并录制组件的一些代码。我在使用变量稀有性组件时,遇到了一个自定义构造函数的编译时错误 public record Break<R extends Record>(R record, String... notifications) { public Break(R record, String... notifications) { System.out.println("record: " + record + "

尝试使用
录制
并录制组件的一些代码。我在使用变量稀有性组件时,遇到了一个自定义构造函数的编译时错误

public record Break<R extends Record>(R record, String... notifications) {

    public Break(R record, String... notifications) {
        System.out.println("record: " + record + " and notifications: " + Arrays.toString(notifications));
        this.record = record;
        this.notifications = notifications;
    }

    // compile error: non canonical record constructor must delegate to another costructor
    public Break(R record) { 
        System.out.println("record: " + record);
        this.record = record;
    }

    public Break() {
        this(null); // this works 
        // actually intelliJ suggests it uses the constructor that is not compiling
    }


    public static void main(String[] args) {
        new Break<>(new Break<>());
    }
}
公共记录中断(R记录、字符串…通知){
公共中断(R记录、字符串…通知){
System.out.println(“记录:+record+”和通知:+array.toString(通知));
this.record=记录;
this.notifications=通知;
}
//编译错误:非规范记录构造函数必须委托给另一个构造函数
公众休息(R纪录){
System.out.println(“记录:+record”);
this.record=记录;
}
公共休息日{
this(null);//这个有效
//实际上intelliJ建议它使用未编译的构造函数
}
公共静态void main(字符串[]args){
新中断(newbreak());
}
}

我想了解的是,当通过另一个自定义构造函数调用类似的构造函数时,如果没有为初始化提供任何组件,该构造函数是如何推断的。

这与变量arity无关。所有记录构造函数链必须在规范构造函数(可以使用紧凑形式指定)中“自底向上”,无论是否为变量arity。这表现为要求每个非规范构造函数必须委托给另一个构造函数;最终,这意味着链在规范中由下而下

您可以使用以下方法修复错误的构造函数:

public Break(R record) {
    this(record);
}

但是,您甚至不需要全部声明这个构造函数,因为规范构造函数已经可以处理
newbreak(r)
形式的调用了。

我的理解是,非规范构造函数不需要只委托给规范构造函数。Java仍然可以解析链并检测循环。因此,假设您的
Break(R记录)
委托给规范构造函数,调用
Break()
仍将成功初始化所有组件。有时我希望可以有绕过规范构造函数的私有构造函数。原因包括,如果我知道传递的数组将来不会被修改,那么就不制作数组的防御副本。可能通过显式调用
super()
来表明这不是意外?当前的解决方法使用ThreadLocals来设置标志,但通常不值得这么做。@JohannesKuhn我想你会发现这样的游戏大多只是解决了问题。你的访问者做防御性拷贝吗?是否更新
Object::equals
以反映这一点?请注意,
Record::equals
中有一个经过改进的契约,它可能会被这样的技巧破坏。我总是问自己:如果
java.lang.String
会是一个记录呢?从一些POV中可以看出这一点。我试图避免的是复制数组两次,所以我想实现一个类似的构造函数。从字符串的演变来看,很明显还需要一个关于如何将记录转换为常规类的故事。问题是反射支持-
类。getRecordComponents
不再起作用了。@JohannesKuhn这样做的方法可能是编写一个类?记住,记录不是一个语法特征(尽管它们的语法很好),它们是一个语义特征——名义元组。记录所能做的一切(几乎),类所能做的一切(除了implement
java.lang.Record
)@JohannesKuhn我同意当前的定义可能会排除一些在语义上仍然是候选的(同意的:罕见的)情况。在更为罕见的情况下,性能差异实际上可能很重要(但我怀疑这是非常罕见的),但仅此一点还不足以得出我们选择了错误的规则集的结论;选择规则需要平衡许多不同的考虑因素,这只是其中之一。设计涉及权衡;在这里,我们排除一些可能的好案例,以排除更多的坏案例。5年后问我我们是否做对了。。。