Concernant la comparaison d'équivalence de type de chaîne en Java

Aperçu

Dans le langage de programmation "Java", "==" est pris en charge comme opérateur de comparaison pour l'équivalence, mais lorsqu'il est utilisé lors de la comparaison de ** types de référence ** qui ne sont pas des ** types primitifs ** tels que les types String Ce sera un résultat de traitement inattendu. L'essentiel est que vous ne devez pas utiliser l'opérateur d'égalité "==" pour comparer si les valeurs des types de référence ** sont égales. ** **

Dans cet article, j'écrirai sur les raisons pour lesquelles vous ne devriez pas utiliser d'opérateurs d'égalité lorsque vous effectuez des comparaisons de type String et ce qui se passe si vous le faites. Cependant, cette fois, l'article se concentre uniquement sur le type String, mais c'est aussi l'histoire du type référence en général.

Notions de base

Type primitif (type de données de base)

Les types primitifs sont des types qui représentent les données elles-mêmes et n'ont aucun comportement pour manipuler les données. Vous ne pouvez pas affecter null à un type primitif.

Par exemple, il existe les types suivants.

Type de référence

Contrairement aux types primitifs, les types référence nécessitent l'utilisation de l'opérateur new pour créer et affecter des instances (entités) à des objets, chacun ayant un comportement spécifique au type. Vous pouvez affecter null au type de référence.

Par exemple, il existe les types suivants. De plus, le fabricant peut définir les types et les processus requis pour traiter l'application autres que les suivants.

Au fait, si vous étudiez une langue utilisant des pointeurs, vous la connaissez probablement déjà. Pour ceux qui disent «** Référence **» en premier lieu, il est recommandé car il est décrit en détail dans l'article suivant. https://qiita.com/hys-rabbit/items/2e94c8722dc8f950e77c

Sujet principal

Que se passe-t-il lorsque vous comparez des types String avec des opérateurs d'égalité?

Tout d'abord, considérez le résultat de sortie en examinant le traitement suivant.

TestEquals.java


public final class TestEquals {
	public static void main(String[] args) {
		final String sequence1 = "test";
		final String newSequence = new String("test");

		System.out.println("Comparaison avec l'opérateur d'égalité 1:");
		System.out.println(sequence1 == newSequence);
	}
}

Maintenant, quel est le résultat de la comparaison de la même chaîne de caractères "test" avec l'opérateur d'égalité? À première vue, les mêmes chaînes de caractères sont comparées, de sorte que le résultat de la comparaison est probablement vrai. ** Cependant, dans le cas ci-dessus, le résultat de la comparaison sera toujours faux. ** **

Pourquoi obtenez-vous ce résultat? En effet, la comparaison avec l'opérateur d'égalité "==" détermine ** si les données sont stockées à la même adresse en mémoire **.

C'est une histoire technique, donc je n'entrerai pas dans les détails ici, mais il est important de se demander ce qu'est la mémoire. Cependant, dans cet article, je ne présenterai que quelques articles recommandés. Si vous pouvez vous le permettre en apprenant, vous voudrez peut-être jeter un coup d'œil.

** Mécanisme de gestion de la mémoire du tas Java ** https://www.atmarkit.co.jp/ait/articles/0504/02/news005.html

** Mémoire vue du programme ** https://qiita.com/shinpeinkt/items/55c0d30754482e8235b9

En d'autres termes, dans le cas ci-dessus, la variable "sequence1" et la variable "newSequence" sont stockées dans différentes zones de la mémoire, donc si vous comparez avec l'opérateur d'égalité, false sera renvoyé.

Supplément

Fondamentalement, la compréhension ci-dessus est suffisante pour l'opérateur d'égalité, Dans certains cas, veuillez les vérifier également.

TestEquals.java


public final class TestEquals {
	public static void main(String[] args) {
		final String sequence1 = "test";
		final String sequence2 = "test";

		System.out.println("Comparaison avec l'opérateur d'égalité 2:");
		System.out.println(sequence1 == sequence2);
	}
}

La différence avec le premier exemple est que la variable "newSequence" a été initialisée à l'aide de l'opérateur new, mais la chaîne "test" est simplement affectée à la variable "sequence2". Quel sera le résultat du traitement dans les cas ci-dessus? Est-ce faux? ** Non, cela sera jugé vrai dans le cas ci-dessus. ** **

Cela est dû à une fonctionnalité Java, et je vais l'expliquer brièvement. Si vous initialisez en affectant la chaîne de caractères "test" à une variable puis initialisez en affectant la chaîne de caractères "test" à une autre variable de la même manière, elle sera gérée dans la même zone de la mémoire. Java a une fonctionnalité intégrée qui vous permet d'effectuer des ajustements comme si vous le faisiez. Par conséquent, dans le cas ci-dessus, le résultat du traitement est vrai.

Comparaison avec la méthode égale

Maintenant, parlons de la méthode equals définie dans la classe String principale. Pour rappel, utilisez la méthode equals comme suit:

TestEquals.java


public final class TestEquals {
	public static void main(String[] args) {
		final String sequence1 = "test";
		final String sequence2 = "test";
		
		System.out.println("Comparaison avec la méthode égale 1:");
		System.out.println(sequence1.equals(sequence2));
		
		final String newSequence = new String("test");
		
		System.out.println("Comparaison avec la méthode égale 2:");
		System.out.println(sequence1.equals(newSequence));
	}
}

En comparant avec la méthode equals, true est renvoyé dans les deux modèles de l'exemple ci-dessus. Maintenant, qui est la méthode equals définie dans la classe String et quel type de traitement est défini?

Fonctionnement de la méthode equals définie dans la classe String

Le code suivant est le traitement de la méthode equals définie dans la classe String.

String.java


    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = length();
            if (n == anotherString.length()) {
                int i = 0;
                while (n-- != 0) {
                    if (charAt(i) != anotherString.charAt(i))
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

À première vue, cela peut sembler difficile, mais si vous regardez comment cela fonctionne en le démontant, c'est une implémentation très simple.

Tout d'abord, la comparaison est effectuée avec l'opérateur d'égalité et true est renvoyé si les références sont égales. C'est le cas de l'initialisation en affectant directement une chaîne de caractères à une variable comme mentionné dans l'exemple précédent.

Ensuite, ce sera le processus de jugement lorsque la destination de référence est différente du bloc suivant. Tout d'abord, il détermine si l'instance de l'objet passé en argument est de type String, et si elle n'est pas de type String, elle renvoie false car ce sont des données complètement différentes en premier lieu. Ensuite, si l'objet argument est de type String, il est vérifié caractère par caractère depuis le début pour voir s'il est égal à la chaîne de caractères à comparer. Enfin, l'implémentation doit retourner true si tous les caractères sont égaux à la cible de comparaison.

De ce qui précède, vous pouvez voir que la méthode equals implémentée dans la classe String couvre toutes les faiblesses de la comparaison avec l'opérateur d'égalité que nous avons vu précédemment.

Attention (pratique courante en Java)

Si vous êtes à l'aise pour lire jusqu'ici, vous avez peut-être remarqué que si la classe String qui utilise la méthode equals devient nulle, une NullPointerException se produira toujours. Par conséquent, en tant qu'utilisateur Java, vous devez suivre les règles ci-dessous.

--Lors de l'utilisation de la méthode eauals, elle doit être sous la forme ** "Constante non nulle .equals (variable ou constante)" **

Autrement dit, l'implémenteur doit s'assurer que la classe String qui utilise la méthode equals n'est pas nulle. Bien sûr, en fonction de l'implémentation, il peut y avoir des situations où il ne peut pas être rendu constant, mais si vous garantissez toujours le traitement du programme, vous devez le concevoir de sorte que null n'entre pas.

finalement

J'écris ça depuis longtemps, mais comment était-ce? Je sais que certaines explications manquent, mais j'espère que cet article sera utile à ceux qui ont commencé à étudier la programmation avec Java.

Matériel de référence

https://morizyun.github.io/java/type-primitive-reference.html - Types primitifs et référence Java https://qiita.com/hys-rabbit/items/2e94c8722dc8f950e77c - Référence Java à comprendre dans la figure https://www.atmarkit.co.jp/ait/articles/0504/02/news005.html --Mécanisme de gestion de la mémoire du tas Java https://qiita.com/shinpeinkt/items/55c0d30754482e8235b9 --Mémoire vue depuis le programme

Recommended Posts

Concernant la comparaison d'équivalence de type de chaîne en Java
[Java] Comparaison correcte du type String
[Java] Comparaison des chaînes de caractères et && et ||
Détermination de type en Java
L'histoire de la comparaison de chaînes de bas niveau en Java
Essayez le type fonctionnel en Java! ①
[Java] Comparaison de la vitesse de conversion de type
J'ai essayé de convertir une chaîne de caractères en un type LocalDate en Java
[Java] Comparaison de vitesse de combinaison de chaînes
Chaîne Java
[Explication facile à comprendre! ] Conversion de type de type de référence en Java
[Java] Aide-mémoire de classe de type de données / chaîne de caractères
Remarques sur les opérateurs utilisant Java ~ Type chaîne ~
[Java] Convertit null du type Object en type String
Toutes les mêmes chaînes de code de hachage en Java
Diviser une chaîne avec ". (Dot)" en Java
Conversion de type Java 8 LocalDateTime (String, java.util.Date)
Conversion de type du type java Big Decimal au type String
[Java] Afficher la chaîne de bits stockée dans la variable de type d'octet sur la console
[Java] Comparaison d'équivalence où les débutants échouent dans la comparaison de chaînes de caractères. Vous n'êtes peut-être même pas conscient de l'erreur! ??
Conversion de type Java
Concernant les modificateurs transitoires et la sérialisation en Java
[Java] Différence entre equals et == dans une chaîne de caractères qui est un type de référence
Lire une chaîne dans un fichier PDF avec Java
Partition en Java
[Java] Remplissage de la chaîne de caractères
Comparaison des chaînes MyBatis
Le type d'intersection introduit dans Java 10 est incroyable (?)
[Java] Type d'énumération
Java Type facultatif
Code pour échapper aux chaînes JSON en Java
Changements dans Java 11
À propos de var utilisé en Java (type de variable locale)
Janken à Java
Java double type
[Java] Comparaison de cartes
Traitement des chaînes Java
Comparaison du framework Java
Mémo organisé dans la tête (Java - type de données)
Conversion de type Java (chaîne, entier, date, calendrier, etc.)
Taux circonférentiel à Java
Chaîne divisée (Java)
Pourquoi la comparaison de classe de type chaîne Java (==) ne peut pas être utilisée
Comment écrire Java String # getBytes dans Kotlin?
FizzBuzz en Java
Exemple de code pour convertir List en List <String> dans Java Stream
[Type de chaîne vs Générateur de chaînes] Différence de vitesse de traitement dans la combinaison de chaînes
[Java] Comparaison de la vitesse d'exécution de la jointure de chaîne (+ opérateur vs StringBuilder)
[Java] Points à noter sur l'inférence de type étendue dans Java 10
Comparaison équivalente de la classe wrapper Java et du type primitif
Lire JSON en Java
Implémentation de l'interpréteur par Java
Faites un blackjack avec Java
Application Janken en Java
Programmation par contraintes en Java
Mettez java8 dans centos7
NVL-ish guy en Java
Joindre des tableaux en Java