J'ai eu l'occasion d'expliquer le mécanisme de référence Java à mes juniors en utilisant la zone de pile et la zone de tas Java. Je me souviens avoir été confus au sujet des références Java alors que je ne connaissais pas la relation entre ces domaines. C'est une bonne opportunité, je vais donc la résumer dans un article.
Une zone de pile et une zone de tas Java existent dans la JVM pour réaliser la référence Java. Les références Java sont réalisées par ces deux zones.
Nom de la zone | Aperçu |
---|---|
Zone de pile | Il contient principalement des informations de référence sur la zone du tas. Il contient également la valeur du type primitif. |
Zone de tas JAVA | La valeur réelle de l'objet est stockée dans cette mémoire. |
Les objets Java (classe, tableau, etc.) ont des informations de référence de zone de tas dans la zone de pile. La valeur réelle est stockée dans la zone du tas.
Les types primitifs ont une gestion de la mémoire différente de celle des objets. Lorsque vous créez une variable de type primitif, elle contient la valeur dans la zone de pile.
Lors du passage d'un objet ou d'une variable de type primitif à un argument de méthode Le contenu de la zone de pile est copié dans une autre zone de pile. Dans le cas ci-dessus, la référence de argA est la même que la variable a. La modification de la valeur référencée dans method1 affecte également la variable a.
Afin de confirmer que le contenu décrit jusqu'à présent est correct, nous expliquerons en comparant le code source avec le résultat de sortie.
Code source
package test;
class Class1 {
String id;
int value;
}
public class Test {
public static void main(String[] args) {
Class1 a = new Class1();
a.id = "ID1";
a.value = 1;
//Opération [1]
Class1 b = a;
//Opération [2]
b.id = "ID2";
b.value = 2;
//Fonctionnement [3]
b = null;
//Quelle est la valeur sortie ici?
System.out.println("id:" + a.id);
System.out.println("value:" + a.value);
}
}
[Détails de l'opération]
Par l'opération [2], la valeur de la destination de référence de la variable a est également réécrite. L'opération [3] supprime la référence à la variable b, mais elle n'affecte pas la variable a avec une pile différente. Par conséquent, le contenu de sortie est le suivant.
Résultat de sortie
id:ID2
value:2
Code source
package test;
class Class1 {
String id;
int value;
}
public class Test {
public static void main(String[] args) {
Class1 a = new Class1();
a.id = "ID1";
a.value = 1;
//Opération [1]
method1(a);
//Quelle est la valeur sortie ici?
System.out.println("id:" + a.id);
System.out.println("value:" + a.value);
}
private static void method1(Class1 argA) {
//Opération [2]
argA.id = "ID2";
argA.value = 2;
}
}
[Détails de l'opération] Par l'opération [2], la valeur de la destination de référence de la variable a est également réécrite. Par conséquent, le contenu de sortie est le suivant.
Résultat de sortie
id:ID2
value:2
Code source
package test;
class Class1 {
String id;
int value;
}
public class Test {
public static void main(String[] args) {
Class1 a = new Class1();
a.id = "ID1";
a.value = 1;
//Opération [1]
method1(a);
//Quelle est la valeur sortie ici?
System.out.println("1ère fois =========");
System.out.println("id:" + a.id);
System.out.println("value:" + a.value);
//Opération [2]
method2(a);
//Quelle est la valeur sortie ici?
System.out.println("Deuxième fois =========");
System.out.println("id:" + a.id);
System.out.println("value:" + a.value);
}
private static void method1(Class1 argA) {
argA = null;
}
private static void method2(Class1 argA) {
argA = new Class1();
argA.id = "ID2";
argA.value = 2;
}
}
[Détails de l'opération] Comme dans l'exemple 2, nous transmettons la variable a comme argument de méthode. La méthode d'opération [1] affecte null et supprime la référence d'argA, mais elle n'affecte pas la variable a avec une pile différente. Puisque la méthode d'opération [2] est une nouvelle classe 1, la destination de référence a changé pour la variable a. La définition des valeurs d'id et de valeur après la modification de la référence n'affecte pas la variable a. Par conséquent, le contenu de sortie est le suivant.
Résultat de sortie
1ère fois =========
id:ID1
value:1
Deuxième fois =========
id:ID1
value:1
Code source
package test;
public class Test {
public static void main(String[] args) {
int a = 1;
//Opération [1]
int b = a;
//Opération [2]
b = 99;
//Quelle est la valeur sortie ici?
System.out.println("1ère fois =========");
System.out.println("a:" + a);
System.out.println("b:" + b);
//Fonctionnement [3]
method1(a);
//Quelle est la valeur sortie ici?
System.out.println("Deuxième fois =========");
System.out.println("a:" + a);
}
private static void method1(int argA) {
//Fonctionnement [4]
argA = 99;
}
}
[Détails de l'opération] Chaque variable de type primitif contient une valeur dans la zone de pile indépendamment. Chaque opération n'affecte pas une autre variable. Par conséquent, le contenu de sortie est le suivant.
Résultat de sortie
1ère fois =========
a:1
b:99
Deuxième fois =========
a:1
Code source
package test;
public class Test {
public static void main(String[] args) {
int a = 0;
//Opération [1]
int[] b = {a};
//Opération [2]
method1(b);
//Quelle est la valeur sortie ici?
System.out.println("a:" + a);
System.out.println("b[0]:" + b[0]);
}
private static void method1(int[] argB) {
//Fonctionnement [3]
argB[0] = 99;
}
}
[Détails de l'opération] Même s'il s'agit d'un type primitif, si vous le conservez sous forme de tableau, sa valeur sera enregistrée dans la zone du tas. La modification du tableau argB dans l'opération [3] affecte le tableau b qui a la même destination de référence. Par conséquent, le contenu de sortie est le suivant.
Résultat de sortie
a:0
b[0]:99
Recommended Posts