L'histoire de la comparaison de chaînes de bas niveau en Java

Cet article est le troisième jour du Shizudai Information LT Tournament Advent Calendar 2019.

introduction

C'est une histoire de bas niveau. Il est facile de lire si Java peut être rendu normal pour le moment. Si vous avez comparé des chaînes de caractères, vous pouvez le lire pour le moment.

la revue(?)

Lorsque vous comparez des chaînes en Java, ne comparez pas avec "==". Utilisez la méthode String # equals.

public class Test {
	public static void main(String[] args) {
		String a = "HelloWorld";
		String b = "Hello";
		b += "World";

		System.out.println(a == b);        // false
		System.out.println(a.equals(b));   // true
	}
}

Attendez une minute, "==" sera vrai

public class Test {
	public static void main(String[] args) {
		String a = "HelloWorld";
		String b = "HelloWorld";

		System.out.println(a == b);       // true
		System.out.println(a.equals(b));  // true
	}
}

Pourquoi?

Mécanisme de "=="

JVM "==" On dit souvent qu'il s'agit d'une comparaison d'emplacements d'adresses, mais regardons de plus près.

En Java, "==" est souvent converti en l'une des instructions JVM, comme "if_acmpne" ou "if_acmpeq", au moment de la compilation.

Une JVM a beaucoup de fichiers de classe générés lorsque vous compilez un fichier Java, non? La machine virtuelle Java (JVM) interprète et exécute le fichier de classe. Les fichiers de classe sont dans un format que beaucoup de gens ne peuvent pas lire (et le font rarement), mais ils sont plus faciles à lire sur une JVM (ordinateur). Puisque la JVM réalise un programme complexe en combinant plusieurs instructions simples, ce qui n'est qu'une seule instruction en Java est souvent convertie en plusieurs instructions dans la JVM. image.png

Instruction JVM et pile d'opérandes

Ensuite, quel type d'instruction est "if_acmpne" ou "if_acmpeq" est une instruction pour en prendre deux dans la pile d'opérandes, vérifier si elles correspondent et passer à la ligne du programme spécifié.

Pile d'opérande ……? La JVM est appelée une machine à pile et n'utilise pas de registres, mais utilise un périphérique appelé «pile» pour effectuer diverses opérations.

La pile d'opérandes est comme un espace de travail. Il est souvent utilisé car il convient parfaitement aux opérations à quatre règles. (Notation polonaise inversée, etc.)

Par exemple, 5 + 12 peuvent être calculés par le mécanisme suivant. image.png

Cependant, la pile d'opérandes en Java n'a qu'un seul élément jusqu'à 32 bits.

Lorsqu'un caractère est représenté par Java, un élément (= 32 bits) de cette pile d'opérandes est consommé. La chaîne est de taille variable. Parfois, nous traitons un caractère, et parfois nous traitons des centaines de caractères comme dans cet article. En d'autres termes, un élément de la pile d'opérandes (= 32 bits) ne peut pas du tout gérer tous les caractères.

Par conséquent, enregistrez la chaîne de caractères dans une autre mémoire et enregistrez l'adresse (adresse sur l'ordinateur) de cette mémoire dans la pile d'opérandes. En conséquence, un élément de la pile d'opérandes (= 32 bits) suffira.

Comme mentionné précédemment, "if_acmpne" et "if_acmpeq" sont extraits de la pile d'opérandes, et lorsqu'ils sont égaux pour "if_acmpeq" et non égaux pour "if_acmpne", ils sautent à une autre ligne spécifiée. (Jump est comme une commande GOTO courante) image.png

En d'autres termes, dans le cas de "if_acmpeq", si les nombres d'adresses sur la pile d'opérandes sont égaux, une instruction de saut sera générée. Dans le deuxième code source de cette page ("Attendez une minute"), "Hello World" a été stocké à la même adresse, il est donc affiché comme vrai.

Pour être vrai ...

Est-il stocké au même endroit?

C'est tout.

Alors, que pensez-vous que ce sera? Veuillez pardonner que le nom est approprié

public class Test {
	public static void main(String[] args) {
		String a = "HelloWorld";
		method1(a);
	}
	
	public static void method1(String c) {
		String k = "HelloWorld";
		System.out.println(k == c);
	}
}

La réponse est «vraie».

Aire constante de classe

Les fichiers de classe Java ont une zone constante. Cette zone constante stocke principalement des chaînes de caractères, etc. lors de la compilation. Des choses comme les nombres magiques et les chaînes magiques (?) Sont stockées dans cette zone constante et sont chargées en mémoire et utilisées lorsque la JVM lit le fichier de classe. Par exemple

System.out.println("Hello Ja! Ja!");

Tels que "Hello Ja! Ja!" Est stocké dans la zone constante et la chaîne de caractères est lue à partir de là.

De plus, le compilateur Java est suffisamment intelligent pour que même si la même chaîne apparaît deux fois, elle sera lue à partir de la même zone constante si elle a été utilisée plus d'une fois auparavant. En d'autres termes, dans le code précédent, même si les méthodes étaient différentes, les adresses étaient identiques car elles faisaient référence à la chaîne «Hello World» dans la zone constante de la même classe.

Si vous regardez la zone constante du fichier de classe, binaire, "Hello World" est correctement enregistré. image.png

En aparté, dans le premier code source de cette page, j'ai volontairement écrit les chaînes en deux parties, "Hello" et "World", afin de séparer la zone de stockage. Le compilateur Java ne semble pas faire grand chose. Les compilateurs C font souvent cela.

Et les égaux?

Il est remplacé par la classe String, et c'est un code qui compare fermement le contenu Le code de l'image ressemble à celui ci-dessous. Pas la maman d'origine.

@Override
public boolean equals(String str) {
	if(this.length() != str.length()) {
		return false;
	}
	for(int i = 0; i < str.length(); i++) {
		if(this.charAt(i) != str.charAt(i)) {    //Vous pouvez récupérer n'importe quel nième caractère avec charAt
			return false;
		}
	}
	return true;
}

Il est linéaire et compare les caractères un par un dans l'ordre de face. Il n'y a pas de problème car un caractère tient en 32 bits.

Résumé

Utilisez la méthode equals lors de la comparaison de chaînes. Lorsque "==" est vrai, il est stocké au même endroit. Hmmm.

L'article du calendrier de l'Avent de demain est également bon! .. Shizudai Information LT Tournament Advent Calendar 2019

Recommended Posts

L'histoire de la comparaison de chaînes de bas niveau en Java
L'histoire de l'écriture de Java dans Emacs
L'histoire de la fabrication d'un Othello ordinaire à Java
L'histoire de l'apprentissage de Java dans la première programmation
[Java] Comparaison de vitesse de combinaison de chaînes
[Édition Java] Histoire de la sérialisation
[Java] Comparaison correcte du type String
Obtenez le résultat de POST en Java
Concernant la comparaison d'équivalence de type de chaîne en Java
L'histoire de ne pas connaître le comportement de String en passant par Java
[Java] Gestion des Java Beans dans la chaîne de méthodes
À propos de l'idée des classes anonymes en Java
Une histoire sur le JDK à l'ère de Java 11
L'histoire de l'oubli de fermer un fichier en Java et de l'échec
Mesurer la taille d'un dossier avec Java
[Java] Comparaison des chaînes de caractères et && et ||
[Java] Obtenir la longueur de la chaîne de paire de substitution
[Java] La partie déroutante de String et StringBuilder
[Note] Java: mesure la vitesse de concaténation de chaînes
Ressentez le passage du temps même à Java
L'histoire de l'acquisition de Java Silver en deux mois de totalement inexpérimenté.
Importer des fichiers de la même hiérarchie en Java
[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! ??
Comparaison de chaînes de caractères: j'ai été pris dans le problème de vérification des compétences de Paisa
Obtenez l'URL de la destination de la redirection HTTP en Java
La comparaison d'énumération est ==, et equals est bonne [Java]
L'histoire d'une exception d'état illégale dans Jetty.
[Java] Récupère le fichier dans le fichier jar quel que soit l'environnement
Modifier la qualité de stockage des images JPEG en Java
L'histoire de la création de DTO, semblable à Dao avec Java, SQLite
Récapitulez les éléments supplémentaires de la classe Optional dans Java 9
L'histoire que .java est également construite dans Unity 2018
Implémentation Java de tri-tree
A été effectué dans l'année de base de la semaine calendaire Java
Une explication rapide des cinq types de statique Java
Mettez le fichier dans les propriétés de string avec la configuration spring xml
20190803_Java & k8s sur Azure L'histoire d'aller au festival
L'histoire du lancement de données BLOB depuis EXCEL dans DBUnit
[Java] Essayez de modifier les éléments de la chaîne Json à l'aide de la bibliothèque
Comptez le nombre de chiffres après la virgule décimale en Java
Comment dériver le dernier jour du mois en Java
L'histoire de la transmission de Java à Heroku à l'aide du pipeline BitBucket
Accéder à l'interface réseau avec Java
[Java] Supprimer les éléments de la liste
Devinez le code de caractère en Java
Diverses méthodes de la classe Java String
Spécifiez l'emplacement Java dans eclipse.ini
Histoire du passage de Java Gold SE8
Comparaison Java à l'aide de la méthode compareTo ()
Décompressez le fichier zip en Java
L'histoire de @ViewScoped dévore la mémoire
Diverses méthodes de la classe String
Liste des membres ajoutés dans Java 9
Analyser l'analyse syntaxique de l'API COTOHA en Java
Liste des types ajoutés dans Java 9
Ordre de traitement dans le programme
J'ai lu la source de String