Lors de la comparaison de tableaux en Java, existe-t-il des différences entre les deux instructions suivantes?
array1.equals(array2);
Arrays.equals(array1, array2);
Et si oui, quels sont-ils?
array1.equals(array2)
est identique à array1 == array2
, c'est-à-dire si c'est le même tableau. Comme @alf le souligne, ce n'est pas ce à quoi la plupart des gens s'attendent.
Arrays.equals(array1, array2)
compare le contenu des tableaux.
De même, array.toString()
peut ne pas être très utile et vous devez utiliser Arrays.toString(array)
.
C'est un problème infâme: .equals()
pour les tableaux est mal brisé, ne l'utilisez jamais, jamais.
Cela dit, ce n'est pas "cassé" comme dans "quelqu'un l'a vraiment mal fait" - c'est juste faire ce qui est défini et non ce qui est normalement attendu. Donc, pour les puristes: tout va bien, et cela signifie aussi, ne l'utilisez pas, jamais.
Maintenant, le comportement attendu de equals
consiste à comparer les données. Le comportement par défaut est de comparer l'identité, car Object
ne contient aucune donnée (pour les puristes: oui, mais ce n'est pas le but); l'hypothèse est la suivante: si vous avez besoin de equals
dans les sous-classes, vous allez l'implémenter. Dans les tableaux, il n'y a pas d'implémentation pour vous, vous n'êtes donc pas censé l'utiliser.
Donc, la différence est que Arrays.equals(array1, array2)
fonctionne comme on peut s'y attendre (c.-à-d. Qu'il compare le contenu), array1.equals(array2)
revient à la mise en oeuvre de Object.equals
, qui compare à son tour l'identité, et donc mieux remplacé par ==
(pour les puristes: oui je sais à propos de null
).
Le problème, c’est que même Arrays.equals(array1, array2)
vous mordra si les éléments du tableau n’implémentent pas correctement equals
. Je sais que c’est une déclaration très naïve, mais il existe un cas très important qui n’est pas évident: considérons un tableau 2D.
Un tableau 2D dans Java est un tableau de tableaux, et le tableau equals
est cassé (ou inutile si vous préférez). Par conséquent, Arrays.equals(array1, array2)
ne fonctionnera pas comme prévu sur les tableaux 2D.
J'espère que ça t'as aidé.
Regardez à l'intérieur de la mise en œuvre des deux méthodes pour les comprendre profondément:
array1.equals(array2);
/**
* Indicates whether some other object is "equal to" this one.
* <p>
* The {@code equals} method implements an equivalence relation
* on non-null object references:
* <ul>
* <li>It is <i>reflexive</i>: for any non-null reference value
* {@code x}, {@code x.equals(x)} should return
* {@code true}.
* <li>It is <i>symmetric</i>: for any non-null reference values
* {@code x} and {@code y}, {@code x.equals(y)}
* should return {@code true} if and only if
* {@code y.equals(x)} returns {@code true}.
* <li>It is <i>transitive</i>: for any non-null reference values
* {@code x}, {@code y}, and {@code z}, if
* {@code x.equals(y)} returns {@code true} and
* {@code y.equals(z)} returns {@code true}, then
* {@code x.equals(z)} should return {@code true}.
* <li>It is <i>consistent</i>: for any non-null reference values
* {@code x} and {@code y}, multiple invocations of
* {@code x.equals(y)} consistently return {@code true}
* or consistently return {@code false}, provided no
* information used in {@code equals} comparisons on the
* objects is modified.
* <li>For any non-null reference value {@code x},
* {@code x.equals(null)} should return {@code false}.
* </ul>
* <p>
* The {@code equals} method for class {@code Object} implements
* the most discriminating possible equivalence relation on objects;
* that is, for any non-null reference values {@code x} and
* {@code y}, this method returns {@code true} if and only
* if {@code x} and {@code y} refer to the same object
* ({@code x == y} has the value {@code true}).
* <p>
* Note that it is generally necessary to override the {@code hashCode}
* method whenever this method is overridden, so as to maintain the
* general contract for the {@code hashCode} method, which states
* that equal objects must have equal hash codes.
*
* @param obj the reference object with which to compare.
* @return {@code true} if this object is the same as the obj
* argument; {@code false} otherwise.
* @see #hashCode()
* @see Java.util.HashMap
*/
public boolean equals(Object obj) {
return (this == obj);
}
tandis que:
Arrays.equals(array1, array2);
/**
* Returns <tt>true</tt> if the two specified arrays of Objects are
* <i>equal</i> to one another. The two arrays are considered equal if
* both arrays contain the same number of elements, and all corresponding
* pairs of elements in the two arrays are equal. Two objects <tt>e1</tt>
* and <tt>e2</tt> are considered <i>equal</i> if <tt>(e1==null ? e2==null
* : e1.equals(e2))</tt>. In other words, the two arrays are equal if
* they contain the same elements in the same order. Also, two array
* references are considered equal if both are <tt>null</tt>.<p>
*
* @param a one array to be tested for equality
* @param a2 the other array to be tested for equality
* @return <tt>true</tt> if the two arrays are equal
*/
public static boolean equals(Object[] a, Object[] a2) {
if (a==a2)
return true;
if (a==null || a2==null)
return false;
int length = a.length;
if (a2.length != length)
return false;
for (int i=0; i<length; i++) {
Object o1 = a[i];
Object o2 = a2[i];
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return true;
}
Soupir. Dans les années 70, j'étais le "programmeur système" (sysadmin) d'un système IBM 370 et mon employeur était membre du groupe d'utilisateurs IBM SHARE. Il arrivait parfois que quelqu'un soumette un APAR (rapport de bogue) sur un comportement inattendu d'une commande CMS et qu'IBM réponde à NOTABUG: la commande fait ce pour quoi elle a été conçue (et ce que dit la documentation).
SHARE a trouvé un moyen de contourner ce problème: BAD - Broken As Designed. Je pense que cela pourrait s’appliquer à cette implémentation d’égaux pour les tableaux.
Il n'y a rien de mal à implémenter Object.equals. L'objet n'a pas de données membres, il n'y a donc rien à comparer. Deux "objets" sont égaux si et seulement s'ils sont, en fait, le même objet (en interne, la même adresse et la même longueur).
Mais cette logique ne s'applique pas aux tableaux. Les tableaux ont des données et vous vous attendez à une comparaison (via égal) pour comparer les données. Idéalement, comme le fait Arrays.deepEquals, mais au moins comme le fait Arrays.equals (comparaison superficielle des éléments).
Le problème est donc que le tableau (en tant qu'objet intégré) ne remplace pas Object.equals. String (en tant que classe nommée) ne substitue Object.equals et donne le résultat attendu.
Les autres réponses données sont correctes: [...]. Equals ([....]) compare simplement les pointeurs et non le contenu. Peut-être qu'un jour quelqu'un corrigera cela. Ou peut-être pas: combien de programmes existants échoueraient si [...]. Égaux comparaient réellement les éléments? Pas beaucoup, je suppose, mais plus que zéro.
Les tableaux héritent de equals()
de Object
et, par conséquent, la comparaison ne renvoie que vrai si le tableau est comparé à lui-même.
D'autre part, Arrays.equals
compare les éléments des tableaux.
Cet extrait élucide la différence:
Object o1 = new Object();
Object o2 = new Object();
Object[] a1 = { o1, o2 };
Object[] a2 = { o1, o2 };
System.out.println(a1.equals(a2)); // prints false
System.out.println(Arrays.equals(a1, a2)); // prints true
Voir aussi Arrays.equals()
. Une autre méthode statique peut également être intéressante: Arrays.deepEquals()
.
La Arrays.equals(array1, array2)
:
vérifiez si les deux tableaux contiennent le même nombre d'éléments et si toutes les paires d'éléments correspondantes dans les deux tableaux sont égales.
La array1.equals(array2)
:
compare l'objet à un autre objet et renvoie true uniquement si les références des deux objets sont identiques à celles de la fonction Object.equals()
La equals()
des tableaux est héritée de Object
, de sorte qu'elle ne regarde pas le contenu des tableaux, elle considère uniquement chaque tableau comme égal à lui-même.
Les méthodes Arrays.equals()
do comparent le contenu des tableaux. Il y a des surcharges pour tous les types primitifs, et celui des objets utilise les méthodes propres à ces objets equals()
.
import Java.util.Arrays;
public class ArrayDemo {
public static void main(String[] args) {
// initializing three object arrays
Object[] array1 = new Object[] { 1, 123 };
Object[] array2 = new Object[] { 1, 123, 22, 4 };
Object[] array3 = new Object[] { 1, 123 };
// comparing array1 and array2
boolean retval=Arrays.equals(array1, array2);
System.out.println("array1 and array2 equal: " + retval);
System.out.println("array1 and array2 equal: " + array1.equals(array2));
// comparing array1 and array3
boolean retval2=Arrays.equals(array1, array3);
System.out.println("array1 and array3 equal: " + retval2);
System.out.println("array1 and array3 equal: " + array1.equals(array3));
}
}
Voici la sortie:
array1 and array2 equal: false
array1 and array2 equal: false
array1 and array3 equal: true
array1 and array3 equal: false
Voyant ce genre de problème, je choisirais personnellement Arrays.equals(array1, array2)
selon votre question pour éviter toute confusion.