use*_*547 15 java arrays java-14 java-record
鉴于以下代码:
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
}
Run Code Online (Sandbox Code Playgroud)
显然,似乎使用了数组的toString,equals方法(而不是静态方法、Arrays::equals、Arrays::deepEquals 或Array::toString)。
所以我猜 Java 14 Records ( JEP 359 ) 不能很好地处理数组,必须使用 IDE 生成相应的方法(至少在 IntelliJ 中,默认情况下会生成“有用”的方法,即它们使用静态方法在Arrays)。
或者还有其他解决方案吗?
Bri*_*etz 26
Java 数组对记录提出了几个挑战,这些挑战为设计增加了许多限制。数组是可变的,它们的相等语义(从 Object 继承)是由身份决定的,而不是内容。
您的示例的基本问题是您希望equals()数组意味着内容相等,而不是引用相等。equals()for记录的(默认)语义基于组件的相等性;在例子中,两个Foo含有不同的阵列记录是不同的,并且该记录被正确地表现。问题是你只是希望平等比较是不同的。
也就是说,你可以用你想要的语义声明一个记录,它只是需要更多的工作,你可能会觉得这是太多的工作。这是一个可以满足您要求的记录:
record Foo(String[] ss) {
Foo { ss = ss.clone(); }
String[] ss() { return ss.clone(); }
boolean equals(Object o) {
return o instanceof Foo
&& Arrays.equals(((Foo) o).ss, ss);
}
int hashCode() { return Objects.hash(Arrays.hashCode(ss)); }
}
Run Code Online (Sandbox Code Playgroud)
它所做的是在进入(在构造函数中)和退出(在访问器中)的过程中进行防御性复制,以及调整相等语义以使用数组的内容。这支持超类中所需的不变量,java.lang.Record即“将记录分解为其组件,然后将组件重建为新记录,产生相等的记录”。
您可能会说“但是工作量太大了,我想使用记录,所以我不必输入所有这些东西。” 但是,记录主要不是一种句法工具(尽管它们在句法上更令人愉快),它们是一种语义工具:记录是名义元组。大多数情况下,紧凑的语法也会产生所需的语义,但如果您想要不同的语义,则必须做一些额外的工作。
Bas*_*que 11
List< Integer > 解决方法解决方法:使用一个List的Integer对象(List< Integer >),而不是基元的阵列(int[])。
在此示例中,我使用Java 9 中添加的功能实例化了一个未指定类的不可修改列表List.of。您也可以将ArrayList, 用于由数组支持的可修改列表。
package work.basil.example;
import java.util.List;
public class RecordsDemo
{
public static void main ( String[] args )
{
RecordsDemo app = new RecordsDemo();
app.doIt();
}
private void doIt ( )
{
record Foo(List < Integer >integers)
{
}
List< Integer > integers = List.of( 1 , 2 );
var foo = new Foo( integers );
System.out.println( foo ); // Foo[integers=[1, 2]]
System.out.println( new Foo( List.of( 1 , 2 ) ).equals( new Foo( List.of( 1 , 2 ) ) ) ); // true
System.out.println( new Foo( integers ).equals( new Foo( integers ) ) ); // true
System.out.println( foo.equals( foo ) ); // true
}
}
Run Code Online (Sandbox Code Playgroud)
解决方法:创建一个IntArray类并将int[].
record Foo(IntArray ints) {
public Foo(int... ints) { this(new IntArray(ints)); }
public int[] getInts() { return this.ints.get(); }
}
Run Code Online (Sandbox Code Playgroud)
不完美,因为您现在必须调用foo.getInts()而不是foo.ints(),但其他一切都按您想要的方式工作。
public final class IntArray {
private final int[] array;
public IntArray(int[] array) {
this.array = Objects.requireNonNull(array);
}
public int[] get() {
return this.array;
}
@Override
public int hashCode() {
return Arrays.hashCode(this.array);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
IntArray that = (IntArray) obj;
return Arrays.equals(this.array, that.array);
}
@Override
public String toString() {
return Arrays.toString(this.array);
}
}
Run Code Online (Sandbox Code Playgroud)
输出
record Foo(IntArray ints) {
public Foo(int... ints) { this(new IntArray(ints)); }
public int[] getInts() { return this.ints.get(); }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1015 次 |
| 最近记录: |