Dado el siguiente código:
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
}
Parece, por supuesto, de esa matriz toString
, equals
los métodos se utilizan (en lugar de los métodos estáticos,Arrays::equals
, Arrays::deepEquals
o Array::toString
).
Así que supongo que Java 14 Records ( JEP 359 ) no funcionan demasiado bien con las matrices, los métodos respectivos tienen que generarse con un IDE (que al menos en IntelliJ, por defecto genera métodos "útiles", es decir, usan los métodos estáticos en Arrays
).
¿O hay alguna otra solución?
java
arrays
java-14
java-record
usuario140547
fuente
fuente
List
lugar de una matriz?toString()
,equals()
y loshashCode()
métodos de un registro se implementan utilizando una referencia invokedynamic. . Si solo el equivalente de la clase compilada pudiera haber estado más cerca de lo que hace el métodoArrays.deepToString
en su método privado sobrecargado hoy, podría haber resuelto los casos primitivos.Object
, ya que eso también podría suceder con las clases definidas por el usuario. por ejemplo, incorrecto es igualinvokedynamic
tiene absolutamente nada que ver con la selección de la semántica; indy es un detalle de implementación pura aquí. El compilador podría haber emitido bytecode para hacer lo mismo; esta era solo una forma más eficiente y flexible de llegar allí. Durante el diseño de los registros se discutió extensamente si utilizar una semántica de igualdad más matizada (como la igualdad profunda para matrices), pero esto causó muchos más problemas de los que supuestamente resolvió.Respuestas:
Las matrices Java plantean varios desafíos para los registros, y estos agregaron una serie de restricciones al diseño. Las matrices son mutables, y su semántica de igualdad (heredada de Object) es por identidad, no por contenido.
El problema básico con su ejemplo es que desea que
equals()
en las matrices signifique igualdad de contenido, no igualdad de referencia. La semántica (predeterminada)equals()
para los registros se basa en la igualdad de los componentes; en su ejemplo, los dosFoo
registros que contienen matrices distintas son diferentes y el registro se comporta correctamente. El problema es que solo desearías que la comparación de igualdad fuera diferente.Dicho esto, puede declarar un registro con la semántica que desee, solo requiere más trabajo y puede sentir que es demasiado trabajo. Aquí hay un registro que hace lo que quieres:
Lo que esto hace es una copia defensiva al entrar (en el constructor) y al salir (en el descriptor de acceso), así como ajustar la semántica de igualdad para usar los contenidos de la matriz. Esto es compatible con el invariante, requerido en la superclase
java.lang.Record
, que "separar un registro en sus componentes y reconstruir los componentes en un nuevo registro, produce un registro igual".Bien podría decir "pero eso es demasiado trabajo, quería usar registros para no tener que escribir todo eso". Pero los registros no son principalmente una herramienta sintáctica (aunque son sintácticamente más agradables), son una herramienta semántica: los registros son tuplas nominales . La mayoría de las veces, la sintaxis compacta también produce la semántica deseada, pero si desea una semántica diferente, debe realizar un trabajo adicional.
fuente
List< Integer >
solución alternaSolución alternativa: utilice a
List
ofInteger
objects (List< Integer >
) en lugar de una matriz de primitivas (int[]
).En este ejemplo, ejemplifico una lista no modificable de clase no especificada usando la
List.of
característica agregada a Java 9. También podría usarArrayList
, para una lista modificable respaldada por una matriz.fuente
Solución alternativa: cree una
IntArray
clase y ajuste elint[]
.No es perfecto, porque ahora tienes que llamar en
foo.getInts()
lugar de hacerlofoo.ints()
, pero todo lo demás funciona de la manera que deseas.Salida
fuente
record
puede consistir en muchos campos, y solo los campos de la matriz se envuelven de esta manera.List
que proporcionan ese tipo de envoltura que uno podría buscar con la solución propuesta aquí. ¿O considera que podría ser una sobrecarga para tales casos de uso?int[]
, entonces aList<Integer>
no es lo mismo, al menos por dos razones: 1) La lista usa mucha más memoria y 2) No hay conversión integrada entre ellos.Integer[]
🡘List<Integer>
es bastante fácil (toArray(...)
yArrays.asList(...)
), peroint[]
🡘List<Integer>
requiere más trabajo y la conversión lleva tiempo, por lo que es algo que no desea hacer todo el tiempo. Si tiene unint[]
y desea almacenarlo en un registro (con otras cosas, de lo contrario, ¿por qué usar un registro?) Y lo necesita como unint[]
archivo, entonces la conversión cada vez que lo necesite está mal.Arrays.equals
,Arrays.toString
sobre laList
implementación utilizada mientras reemplazas laint[]
que se sugiere en la otra respuesta. (Suponiendo que ambas sean soluciones alternativas de todos modos.)