下面是一个例子:
public static void main(String[] args) {
record Foo(int[] ints){}
var ints = new int[]{1, 2};
var foo = new Foo(ints);
System.out.println(foo); // Foo[ints=[I@6433a2]
System.out.println(new Foo(new int[]{1,2}).equals(new Foo(new int[]{1,2}))); // false
System.out.println(new Foo(ints).equals(new Foo(ints))); //true
System.out.println(foo.equals(foo)); // true
}
字符串
显然,似乎使用了数组的toString
,equals
方法(而不是静态方法,Arrays::equals
,Arrays::deepEquals
或Array::toString
)。
所以我猜Java 14 Records(JEP 359)不能很好地处理数组,相应的方法必须用IDE生成(至少在IntelliJ中,默认情况下会生成“有用”的方法,即它们使用Arrays
中的静态方法)。
还是有其他解决办法?
3条答案
按热度按时间xnifntxz1#
Java数组对记录提出了一些挑战,这些挑战给设计增加了一些约束。数组是可变的,它们的相等语义(继承自Object)是通过标识,而不是内容。
你的例子的基本问题是,你希望数组上的
equals()
意味着内容相等,而不是引用相等。在您的示例中,包含不同数组的两个Foo
记录**不同,记录的行为是正确的。问题是你只是希望相等比较是不同的。也就是说,你可以用你想要的语义来声明一条记录,这只需要更多的工作,你可能会觉得这是太多的工作。下面是一条记录,它可以做你想要的:
字符串
这是一个防御性的拷贝,在传入(在构造函数中)和传出(在访问器中)的过程中,以及调整相等语义以使用数组的内容。这支持超类
java.lang.Record
中所需的不变式,即“将一个记录分解为它的组件,并将组件重构为一个新记录,产生一个相等的记录”。你可能会说“但是这太麻烦了,我想使用记录,这样我就不必输入所有的东西了。”但是,记录主要不是一个语法工具(尽管它们在语法上更令人愉快),它们是一个语义工具:记录是 * 名义元组 *。大多数情况下,紧凑语法也会产生所需的语义,但是如果你想要不同的语义,你必须做一些额外的工作。
8nuwlpux2#
List< Integer >
解决方法解决办法:使用
Integer
对象的List
(List< Integer >
),而不是基元数组(int[]
)。在这个例子中,我使用Java 9中添加的
List.of
特性示例化了一个不可修改的未指定类的列表。对于一个由数组支持的可修改列表,您也可以使用ArrayList
。字符串
qkf9rpyu3#
IntArray
类并 Packageint[]
。字符串
并不完美,因为您现在必须调用
foo.getInts()
而不是foo.ints()
,但其他一切都按照您想要的方式工作。型
型