Dado o seguinte 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
}
Ao que parece, obviamente, que do array toString
, equals
os métodos são utilizados (em vez de métodos estáticos, Arrays::equals
, Arrays::deepEquals
ou Array::toString
).
Então, acho que o Java 14 Records ( JEP 359 ) não funciona muito bem com matrizes, os respectivos métodos precisam ser gerados com um IDE (que pelo menos no IntelliJ, por padrão, gera métodos "úteis", ou seja, eles usam os métodos estáticos in Arrays
).
Ou existe alguma outra solução?
java
arrays
java-14
java-record
user140547
fonte
fonte
List
vez de uma matriz?toString()
,equals()
ehashCode()
de um registro são implementados usando uma referência dinâmica invocada. . Se apenas o equivalente da classe compilada pudesse estar mais próximo do que o métodoArrays.deepToString
faz hoje em seu método privado sobrecarregado, ele pode ter sido resolvido para os casos primitivos.Object
, pois isso também pode acontecer com as classes definidas pelo usuário. por exemplo, iguais incorretosinvokedynamic
tem absolutamente nada a ver com a seleção da semântica; indy é um puro detalhe de implementação aqui. O compilador poderia ter emitido o bytecode para fazer a mesma coisa; essa era apenas uma maneira mais eficiente e flexível de chegar lá. Foi discutido extensivamente durante o design dos registros se seria usada uma semântica de igualdade mais sutil (como igualdade profunda para matrizes), mas isso acabou causando muito mais problemas do que supostamente resolvia.Respostas:
As matrizes Java representam vários desafios para os registros, e isso adicionou uma série de restrições ao design. As matrizes são mutáveis e sua semântica de igualdade (herdada de Object) é por identidade, não por conteúdo.
O problema básico do seu exemplo é que você deseja que
equals()
em matrizes signifique igualdade de conteúdo, não referência a igualdade. A semântica (padrão)equals()
para registros é baseada na igualdade dos componentes; no seu exemplo, os doisFoo
registros contendo matrizes distintas são diferentes e o registro está se comportando corretamente. O problema é que você apenas deseja que a comparação de igualdade seja diferente.Dito isto, você pode declarar um registro com a semântica desejada, basta apenas mais trabalho e você pode achar que é muito trabalho. Aqui está um registro que faz o que você deseja:
O que isso faz é uma cópia defensiva na entrada (no construtor) e na saída (no acessador), além de ajustar a semântica da igualdade para usar o conteúdo da matriz. Isso suporta o invariante, exigido na superclasse
java.lang.Record
, que "desmontar um registro em seus componentes e reconstruir os componentes em um novo registro, produz um registro igual".Você pode dizer "mas isso é muito trabalho, eu queria usar registros para não precisar digitar tudo isso". Porém, os registros não são primariamente uma ferramenta sintática (embora sejam sintaticamente mais agradáveis), são uma ferramenta semântica: registros são tuplas nominais . Na maioria das vezes, a sintaxe compacta também produz a semântica desejada, mas se você quiser uma semântica diferente, precisará fazer algum trabalho extra.
fonte
List< Integer >
GambiarraSolução alternativa: use um
List
deInteger
objetos (List< Integer >
) em vez de uma matriz de primitivas (int[]
).Neste exemplo, instanciamos uma lista não modificável de classe não especificada usando o
List.of
recurso adicionado ao Java 9. Você também pode usarArrayList
uma lista modificável apoiada por uma matriz.fonte
Solução alternativa: crie uma
IntArray
classe e envolva oint[]
.Não é perfeito, porque agora você precisa ligar em
foo.getInts()
vez defoo.ints()
, mas tudo funciona da maneira que você deseja.Resultado
fonte
record
pode consistir em muitos campos e apenas os campos da matriz são agrupados dessa maneira.List
que fornecem o tipo de embalagem que se pode buscar com a solução proposta aqui. Ou você considera que isso pode ser uma sobrecarga para esses casos de uso?int[]
, então aList<Integer>
não é o mesmo, por pelo menos dois motivos: 1) A lista usa muito mais memória e 2) Não há conversão interna entre eles.Integer[]
🡘List<Integer>
é bastante fácil (toArray(...)
eArrays.asList(...)
), masint[]
🡘List<Integer>
exige mais trabalho e a conversão leva tempo, portanto é algo que você não deseja fazer o tempo todo. Se você possuiint[]
e deseja armazená-lo em um registro (com outras coisas, caso contrário, por que usar um registro), e precisa dele como umint[]
, então a conversão sempre que precisar é errada.Arrays.equals
,Arrays.toString
sobre aList
implementação usada ao substituir oint[]
sugerido na outra resposta. (Supondo que ambas sejam soluções alternativas de qualquer maneira.)