Mécanisme de référence Java (pile et tas)

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.

Mécanisme de réalisation de référence Java

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.

Différences dans la façon dont les objets et les valeurs de type primitif sont conservés

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.

Comportement lors du passage aux arguments de méthode

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. 引数へ渡した時の挙動.png 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.

Exemple de code source

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.

Exemple 1

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] 例1.png

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

Exemple 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] 例2.png 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

Exemple 3

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

Exemple 4

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] スクリーンショット 2020-06-02 0.58.52.png 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

Exemple 5

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] 例5.png 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

Mécanisme de référence Java (pile et tas)
[Java] Zone de pile et zone statique
Java passe par valeur et passe par référence
A propos des types primitifs et des types de référence Java
Types de données de base et types de référence Java
noyau java: compilateur HotSpot et tas C
[Java] Mécanisme de calcul, opérateurs et conversion de type
Logique du numéro de page et code de référence (java)
Java et JavaScript
XXE et Java
référence de la méthode java8
Matériaux de référence JAVA
Ma référence Java
[Java] Filtrer les traces de pile
Getter et Setter (Java)
[Java] Thread et exécutable
Java vrai et faux
Organiser le mécanisme de Java GC
[Java] Comparaison des chaînes de caractères et && et ||
Java - Sérialisation et désérialisation
[Java] Arguments et paramètres
A propos du type de données de base Java et de la mémoire du type de référence
timedatectl et Java TimeZone
[Java] Branchement et répétition
[Java] Types de variables et types
java (classe et instance)
[Java] Surcharge et remplacement
Résolution avec Ruby, Perl et Java AtCoder ABC 113 C Reference
[Java] Différence entre l’affectation d’une variable de type de base et l’affectation d’une variable de type de référence
[Java] Différence entre l'erreur de débordement de pile et l'erreur de mémoire insuffisante
Etudier Java # 2 (\ marque et opérateur)
[Java] Référence de classe de wrapper Integer
Java version 8 et fonctionnalités ultérieures
Type de données de base et type de référence
Référence du service Java VB.net à mi-chemin
[Java] Différence entre == et égal
Poney et fermeture de capacité de référence
Mécanisme de commande et outils de gestion
[Java] Classe générique et méthode générique
Programmation Java (variables et données)
Cryptage et décryptage Java PDF
Java et Iterator Part 1 External Iterator Edition
Instructions Java if et switch
Définition et instanciation de classe Java
Apache Hadoop et Java 9 (partie 1)
[Java] À propos de String et StringBuilder
[Java] HashCode et remplacement égal
☾ Instruction Java / Repeat et instruction de contrôle de répétition
Méthodes Java et surcharges de méthodes
java Generics T et? Différence
Avantages et inconvénients de Java
java (branchement conditionnel et répétition)
À propos du package Java et de l'importation
Journal de trace de pile Java NullPointerException
[Java] Téléchargez une image et convertissez-la en Base64
Histoire de remplacement C # et Java
Méthodes et classes abstraites Java
Instructions Java while et for
Encapsulation Java et getters et setters
Mécanisme et caractéristiques de la classe d'implémentation Collection souvent utilisés en Java