记录类总是有一个所谓的canonical constructor,它需要为您声明的所有字段提供参数.默认情况下,该构造函数将由编译器生成,但您可以提供自己的构造函数,关键是:在运行时,每个记录都可以使用canonical constructor.
以下是Java Language Specification人的一句话:
为了确保其记录组件的正确初始化,记录类不会隐式声明默认构造函数(§8.8.9).相反,record class有一个canonical constructor,显式或隐式声明为记录类的101.
所有non-canonical constructors都是具有不同于canonical的签名的构造函数,就像您的 case 构造函数期望一个参数ClassA(String)
一样,应该使用所谓的explicit constructor invocation(即使用this()
)将调用委托给canonical constructor(正如您所做的那样),否则此类构造函数将无法编译.
记录声明可以包含非规范构造函数的构造函数声明.出现记录声明102(§8.8.7.1
)中的101,或编译时错误.
100由于您声明了一个包含two个字段的记录,并且您还需要一个non-canonical构造函数,该构造函数需要one个参数,因此将有两个构造函数:canonical和non-canonical.没有解决方法.
101,正如@Brian Goetz正确指出的那样,canonical constructor也值得override.否则,由于可能使用具有不同逻辑的两个构造函数,记录的第二个参数是否为第一个参数的大写版本将存在歧义.
如果我们将记录定义如下:
public record ClassA(String foo, String bar) {
public ClassA(String foo) {
this(foo, foo.toUpperCase(Locale.ROOT));
}
}
代码如下:
System.out.println(new ClassA("foo", "arbitrary string which not FOO"));
System.out.println(new ClassA("foo"));
将产生输出:
ClassA[foo=foo, bar=arbitrary string which not FOO] // unexpected result
ClassA[foo=foo, bar=FOO] // desired result
为了确保第二个参数在任何情况下都等于第一个变为大写的参数,我们必须覆盖canonical constructor:
public record ClassA(String foo, String bar) {
public ClassA(String foo) {
this(foo, foo); // doesn't matter what would be provided as the second argument
}
public ClassA(String foo, String bar) {
this.foo = foo;
this.bar = foo.toUpperCase(Locale.ROOT);
}
}