Cet article est le troisième jour du Shizudai Information LT Tournament Advent Calendar 2019.
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.
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
}
}
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?
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.
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.
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)
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.
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».
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é.
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.
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.
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