La méthode equals () en Java fonctionne de manière inattendue sur le type de données long

Considérons d’abord les expressions suivantes en Java.

Integer temp = new Integer(1); System.out.println(temp.equals(1)); if(temp.equals(1)) { System.out.println("The if block executed."); } 

Toutes ces déclarations fonctionnent très bien. Cela ne fait aucun doute. L’expression temp.equals(1) est évaluée à true comme prévu et la seule instruction du bloc if est exécutée en conséquence.


Maintenant, lorsque je change le type de données de Integer à Long , l’instruction temp1.equals(1) est évaluée de manière inattendue à false comme suit.

 Long temp1 = new Long(1); System.out.println(temp1.equals(1)); if(temp1.equals(1)) { System.out.println("The if block executed."); } 

Ce sont les déclarations équivalentes à celles mentionnées dans l’extrait précédent, mais le type de données a été modifié et leur comportement est exactement opposé.

L’expression temp1.equals(1) est évaluée à false et, par conséquent, la seule instruction dans le bloc if n’est pas exécutée à l’inverse des instructions précédentes. Comment?

Vous comparez un Long à un int . Le javadoc pour java.lang.Long#equals dit que la méthode equals

Compare cet object à l’object spécifié. Le résultat est vrai si et seulement si l’argument n’est pas null et est un object long qui contient la même valeur long que cet object.

Essayez plutôt System.out.println(new Long(1).equals(1L)); Maintenant que vous comparez un Long à un Long au lieu d’un Long à un Integer , il sera imprimé true .

La valeur littérale 1 n’est pas long , c’est un int . Essayez plutôt le code ci-dessus:

 System.out.println(temp1.equals(1L)); 

Et

 if (temp1.equals(1L)) 

Comme vous pouvez le constater, placer un L après la valeur littérale 1 indique qu’il s’agit d’une valeur long , puis les comparaisons fonctionnent comme prévu.

La raison pour laquelle vous pouvez faire cette comparaison est due à la sélection automatique en Java.

La méthode que vous appelez est la suivante:

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Long.html#equals(java.lang.Object )

qui compare votre object Long à un autre object, et non à une primitive réelle int.

Qu’est-ce qui se passe lorsque vous appelez la méthode est que votre integer(1) primitif integer(1) est en train de générer automatiquement un Object(Integer) alors vous appelez efficacement:

 new Long(1).equals(new Integer(1)); 

c’est pourquoi cela échoue.

C’est pourquoi si vous appelez

 new Long(1).equals(1L) 

Cela fonctionnerait, car Java remplira automatiquement le 1L ( long primitif, pas int ) dans un object Long , pas un object Integer .

Selon la page de Javadoc sur Long , la méthode .equals évaluée que si

  1. L’argument est un object Long
  2. Si (1) est vrai, les objects Long doivent avoir des valeurs égales

Dans votre scénario, 1 est un object int et non pas un object Long . Par conséquent, il échoue (1) et est donc évalué à false. Si vous devez tester long , utilisez plutôt 1L .

Java est paresseux.

Lorsque vous effectuez la comparaison suivante, java convertit automatiquement l’int en un long (car long peut contenir n’importe quelle valeur qu’un int peut contenir). Et la comparaison se situe entre deux longues et non deux pouces.

 int i = 1; long l = 1L; boolean b = i == l; 

Java est capable de le faire car les informations de type sur i et l sont connues à la compilation et lors de la comparaison. Toutefois, lorsque vous utilisez la version encadrée, le type peut être connu au moment de la compilation, mais pas lors de la comparaison. Cela est dû au fait que la comparaison doit être effectuée dans une méthode equals, et puisque equals prend Object en tant que paramètre, les informations de type sont perdues. Ainsi, Java est paresseux et ne vérifie que si deux nombres encadrés sont égaux s’ils sont tous deux des instances de la même classe Number (par exemple, Integer, ou Long, ou les deux, etc …).

Il s’avère que le seul moyen totalement fiable de comparer deux nombres de type inconnu à l’exécution est de convertir les deux en chaînes et les deux en BigDecimal, puis d’utiliser la méthode compareTo (et non pas égale). Bien que si vous savez que vous n’allez jamais avoir de longues années, la vie est plus simple, vous pouvez simplement faire ce qui suit.

 Number n0 = new Long(1L); Number n1 = new Integer(1); boolean equal = n0.longValue() == n1.longValue(); 

Ce comportement est cohérent avec la conversion automatique du 1 en un Integer qui est ensuite égal à un autre Integer(1) . Comparer un Long à un Integer donne un résultat false .

Si vous 1L pour comparer à Long cela donnerait une true .

Temp1 long = nouveau long (1); System.out.println (temp1.equals (1));

if (temp1.equals (1)) {System.out.println (“Le bloc if exécuté.”); }

dans ce code, temp1.equals(1) compare un object Long un object Integer qui donne le résultat faux, on peut le corriger en utilisant 1L au lieu de 1 temp1.equals(1L) par exemple temp1.equals(1L) , en faisant cela on compare Objet Long avec un Long et donne le résultat TRUE

L’implémentation de la méthode equals() de la classe Long illustre pourquoi:

 public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false; } 

La méthode equals dans Java.lang.Long commence par une vérification instanceOf Long uniquement après la comparaison de la valeur.

 public boolean equals(Object obj) { if (obj instanceof Long) { return value == ((Long)obj).longValue(); } return false; } 

Donc, si vous allez utiliser et la valeur entière à la place d’une valeur longue, le premier échec échouera et vous obtiendrez donc un résultat faux.

Vous pouvez comparer les valeurs Long / Entier sans utiliser equals (). Cela n’est nécessaire que lorsque vous comparez des chaînes, autant que je sache.