【问题标题】:Why is the variable arity record component not inferred with custom constructor?为什么不使用自定义构造函数推断变量arity record 组件?
【发布时间】:2021-01-15 18:45:48
【问题描述】:

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<>());
    }
}

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

【问题讨论】:

  • 我的理解是非规范构造函数不需要只委托给规范构造函数。 Java 仍然可以解析链并检测循环。因此,假设您的 Break(R record) 委托给规范构造函数,调用 Break() 仍然会成功初始化所有组件。

标签: java arity java-record java-16


【解决方案1】:

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

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

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

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

【讨论】:

  • 有时我希望我可以拥有绕过规范构造函数的私有构造函数。原因包括如果我知道传递的数组将来不会被修改,则不制作数组的防御性副本。也许通过显式调用super() 来表明这不是意外?当前的解决方法使用 ThreadLocals 设置标志 - 但通常不值得这样做。
  • @JohannesKuhn 我想你会发现这类游戏大多只是解决问题。你的访问者做防御性副本吗?您是否更新 Object::equals 以反映这一点?请注意,Record::equals 中有一个精炼的合同,可能会被此类技巧破坏。
  • 我总是问自己:如果java.lang.String 会成为记录呢?从几个 POV 来看是有道理的。我尽量避免将数组复制两次,所以我想实现一个像this 这样的构造函数。看看 String 的演变,很明显还需要一个关于如何将记录转换为常规类的故事。问题在于反射支持 - Class.getRecordComponents 不再起作用。
  • @JohannesKuhn 也许这样做的方法是编写一个类?请记住,记录不是语法特征(尽管它们的语法很好),它们是语义特征——名义元组。记录可以做的一切(几乎),类可以做(除了实现java.lang.Record。)
  • @JohannesKuhn 我同意当前的定义可能会排除一些(同意:罕见)在语义上仍然是候选的情况。在更罕见的情况下,性能差异实际上可能很重要(但我怀疑这种情况非常罕见。)但仅凭这一点还不足以断定我们选择了错误的规则集;选择规则涉及平衡许多不同的考虑因素,这只是其中之一。设计涉及权衡;在这里,我们排除了一些可能的好案例,以排除更多的坏案例。 5年后问我我们是否做对了......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-17
  • 1970-01-01
  • 1970-01-01
  • 2011-11-23
相关资源
最近更新 更多