Étant donné le code suivant:
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
}
Il semble, de toute évidence, de ce tableau toString
, les equals
méthodes sont utilisées ( au lieu de méthodes statiques, Arrays::equals
, Arrays::deepEquals
ou Array::toString
).
Donc je suppose que les enregistrements Java 14 ( JEP 359 ) ne fonctionnent pas trop bien avec les tableaux, les méthodes respectives doivent être générées avec un IDE (qui au moins dans IntelliJ, génère par défaut des méthodes "utiles", c'est-à-dire qu'elles utilisent les méthodes statiques dans Arrays
).
Ou existe-t-il une autre solution?
java
arrays
java-14
java-record
user140547
la source
la source
List
au lieu d'un tableau?toString()
,equals()
et leshashCode()
méthodes d'un enregistrement sont mises en œuvre en utilisant une référence invokedynamic. . Si seulement l'équivalent de classe compilé aurait pu être plus proche de ce que fait la méthodeArrays.deepToString
dans sa méthode privée surchargée aujourd'hui, il aurait pu résoudre les cas de primitives.Object
, car cela pourrait également arriver avec les classes définies par l'utilisateur. par exemple des égaux incorrectsinvokedynamic
n'a absolument rien à voir avec la sélection de la sémantique; indy est un pur détail d'implémentation ici. Le compilateur aurait pu émettre du bytecode pour faire la même chose; c'était juste un moyen plus efficace et plus flexible pour y arriver. Lors de la conception des enregistrements, il a été longuement discuté de l'opportunité d'utiliser une sémantique d'égalité plus nuancée (telle qu'une égalité profonde pour les tableaux), mais cela s'est avéré causer bien plus de problèmes qu'il n'en aurait résolu.Réponses:
Les tableaux Java posent plusieurs défis pour les enregistrements, et ceux-ci ont ajouté un certain nombre de contraintes à la conception. Les tableaux sont modifiables et leur sémantique d'égalité (héritée d'Object) est basée sur l'identité et non sur le contenu.
Le problème de base avec votre exemple est que vous souhaitez que
equals()
sur les tableaux signifie l'égalité de contenu, pas l'égalité de référence. La sémantique (par défaut)equals()
pour les enregistrements est basée sur l'égalité des composants; dans votre exemple, les deuxFoo
enregistrements contenant des tableaux distincts sont différents et l'enregistrement se comporte correctement. Le problème est que vous souhaitez juste que la comparaison d'égalité soit différente.Cela dit, vous pouvez déclarer un enregistrement avec la sémantique que vous souhaitez, cela prend juste plus de travail, et vous pouvez penser que c'est trop de travail. Voici un enregistrement qui fait ce que vous voulez:
Ce que cela fait, c'est une copie défensive à l'entrée (dans le constructeur) et à la sortie (dans l'accesseur), ainsi qu'en ajustant la sémantique d'égalité pour utiliser le contenu du tableau. Cela prend en charge l'invariant, requis dans la superclasse
java.lang.Record
, que "démonter un enregistrement dans ses composants et reconstruire les composants dans un nouvel enregistrement, donne un enregistrement égal".Vous pourriez bien dire "mais c'est trop de travail, je voulais utiliser des disques donc je n'ai pas eu à taper tout ça." Mais, les enregistrements ne sont pas principalement un outil syntaxique (bien qu'ils soient syntaxiquement plus agréables), ils sont un outil sémantique: les enregistrements sont des tuples nominaux . La plupart du temps, la syntaxe compacte produit également la sémantique souhaitée, mais si vous voulez une sémantique différente, vous devez faire un travail supplémentaire.
la source
List< Integer >
solution de contournementSolution: Utiliser un
List
desInteger
objets (List< Integer >
) plutôt que de tableau de primitives (int[]
).Dans cet exemple, j'instancie une liste non modifiable de classe non spécifiée en utilisant la
List.of
fonctionnalité ajoutée à Java 9. Vous pouvez tout aussi bien l'utiliserArrayList
, pour une liste modifiable appuyée par un tableau.la source
Solution: créez une
IntArray
classe et encapsulez le fichierint[]
.Pas parfait, car vous devez maintenant appeler
foo.getInts()
au lieu defoo.ints()
, mais tout le reste fonctionne comme vous le souhaitez.Production
la source
record
peut être composé de plusieurs champs, et seuls les champs du tableau sont enveloppés comme ceci.List
qui fournissent ce type d'emballage que l'on pourrait rechercher avec la solution proposée ici. Ou pensez-vous que cela pourrait être une surcharge pour de tels cas d'utilisation?int[]
, alors aList<Integer>
n'est pas le même, pour au moins deux raisons: 1) La liste utilise beaucoup plus de mémoire, et 2) Il n'y a pas de conversion intégrée entre eux.Integer[]
🡘List<Integer>
est assez facile (toArray(...)
etArrays.asList(...)
), maisint[]
🡘 demandeList<Integer>
plus de travail et la conversion prend du temps, c'est donc quelque chose que vous ne voulez pas faire tout le temps. Si vous en avez unint[]
et que vous souhaitez le stocker dans un enregistrement (avec d'autres éléments, sinon pourquoi utiliser un enregistrement) et queint[]
vous en avez besoin en tant que , la conversion à chaque fois que vous en avez besoin est incorrecte.Arrays.equals
, parArrays.toString
rapport à laList
mise en œuvre utilisée tout en remplaçant leint[]
comme suggéré dans l'autre réponse. (En supposant que ces deux solutions soient de toute façon.)