Pass-by-Value en tant que mécanisme de transmission de paramètres en Java

1. Introduction

Les deux modes les plus courants de transmission d'arguments aux méthodes sont le «passage par valeur» et le «passage par référence». Différents langages de programmation utilisent ces concepts de différentes manières. En ce qui concerne Java, tout est strictement Pass-by-Value .

Dans ce didacticiel, nous allons illustrer comment Java transmet les arguments pour différents types.

2. Pass-by-Value vs Pass-by-Reference

Commençons par certains des différents mécanismes pour passer des paramètres aux fonctions:

  • valeur
  • référence
  • résultat
  • valeur-résultat
  • Nom

Les deux mécanismes les plus courants dans les langages de programmation modernes sont «Pass-by-Value» et «Pass-by-Reference». Avant de continuer, discutons-en d'abord:

2.1. Valeur Pass-by-Value

Lorsqu'un paramètre est pass-by-value, l'appelant et la méthode appelée opèrent sur deux variables différentes qui sont des copies l'une de l'autre. Toute modification d'une variable ne modifie pas l'autre.

Cela signifie que lors de l'appel d'une méthode, les paramètres passés à la méthode appelée seront des clones des paramètres d'origine. Toute modification effectuée dans la méthode de l'appelant n'aura aucun effet sur les paramètres d'origine de la méthode de l'appelant.

2.2. Pass-by-Reference

Lorsqu'un paramètre est pass-by-reference, l'appelant et l'appelé opèrent sur le même objet.

Cela signifie que lorsqu'une variable est pass-by-reference, l'identifiant unique de l'objet est envoyé à la méthode. Toute modification apportée aux membres de l'instance du paramètre entraînera la modification de la valeur d'origine.

3. Passage de paramètres en Java

Les concepts fondamentaux de tout langage de programmation sont les «valeurs» et les «références». En Java, les variables primitives stockent les valeurs réelles, tandis que les non-primitives stockent les variables de référence qui pointent vers les adresses des objets auxquels elles font référence. Les valeurs et les références sont stockées dans la mémoire de la pile.

Les arguments en Java sont toujours passés par valeur. Lors de l'appel de méthode, une copie de chaque argument, qu'il s'agisse d'une valeur ou d'une référence, est créée dans la mémoire de la pile qui est ensuite transmise à la méthode.

Dans le cas des primitives, la valeur est simplement copiée dans la mémoire de la pile qui est ensuite transmise à la méthode appelée; dans le cas de non-primitives, une référence dans la mémoire de pile pointe vers les données réelles qui résident dans le tas. Lorsque nous passons un objet, la référence dans la mémoire de la pile est copiée et la nouvelle référence est transmise à la méthode.

Voyons maintenant cela en action à l'aide de quelques exemples de code.

3.1. Passer des types primitifs

Le langage de programmation Java comprend huit types de données primitifs. Les variables primitives sont directement stockées dans la mémoire de la pile. Chaque fois qu'une variable de type de données primitive est passée comme argument, les paramètres réels sont copiés dans des arguments formels et ces arguments formels accumulent leur propre espace dans la mémoire de la pile.

La durée de vie de ces paramètres formels ne dure que tant que cette méthode est en cours d'exécution, et au retour, ces arguments formels sont effacés de la pile et sont rejetés.

Essayons de le comprendre à l'aide d'un exemple de code:

public class PrimitivesUnitTest { @Test public void whenModifyingPrimitives_thenOriginalValuesNotModified() { int x = 1; int y = 2; // Before Modification assertEquals(x, 1); assertEquals(y, 2); modify(x, y); // After Modification assertEquals(x, 1); assertEquals(y, 2); } public static void modify(int x1, int y1) { x1 = 5; y1 = 10; } } 

Essayons de comprendre les assertions dans le programme ci-dessus en analysant comment ces valeurs sont stockées en mémoire:

  1. Les variables « et « dans la méthode principale sont des types primitifs et leurs valeurs sont directement stockées dans la mémoire de la pile
  2. Lorsque nous appelons la méthode modify () , une copie exacte de chacune de ces variables est créée et stockée à un emplacement différent dans la mémoire de la pile
  3. Toute modification de ces copies n'affecte qu'eux et laisse les variables d'origine inchangées

3.2. Passer des références d'objets

In Java, all objects are dynamically stored in Heap space under the hood. These objects are referred from references called reference variables.

A Java object, in contrast to Primitives, is stored in two stages. The reference variables are stored in stack memory and the object that they're referring to, are stored in a Heap memory.

Whenever an object is passed as an argument, an exact copy of the reference variable is created which points to the same location of the object in heap memory as the original reference variable.

As a result of this, whenever we make any change in the same object in the method, that change is reflected in the original object. However, if we allocate a new object to the passed reference variable, then it won't be reflected in the original object.

Let's try to comprehend this with the help of a code example:

public class NonPrimitivesUnitTest { @Test public void whenModifyingObjects_thenOriginalObjectChanged() { Foo a = new Foo(1); Foo b = new Foo(1); // Before Modification assertEquals(a.num, 1); assertEquals(b.num, 1); modify(a, b); // After Modification assertEquals(a.num, 2); assertEquals(b.num, 1); } public static void modify(Foo a1, Foo b1) { a1.num++; b1 = new Foo(1); b1.num++; } } class Foo { public int num; public Foo(int num) { this.num = num; } }

Let's analyze the assertions in the above program. We have passed objects a and b in modify() method that has the same value 1. Initially, these object references are pointing to two distinct object locations in a heap space:

When these references a and b are passed in the modify() method, it creates mirror copies of those references a1 and b1 which point to the same old objects:

Dans la méthode modify () , lorsque nous modifions la référence a1 , cela change l'objet d'origine. Cependant, pour une référence b1, nous avons affecté un nouvel objet. Donc, il pointe maintenant vers un nouvel objet dans la mémoire du tas.

Toute modification apportée à b1 ne reflétera rien dans l'objet d'origine:

4. Conclusion

Dans cet article, nous avons examiné comment le passage de paramètres est géré dans le cas des primitives et des non-primitives.

Nous avons appris que le passage de paramètres en Java est toujours Pass-by-Value. Cependant, le contexte change selon qu'il s'agit de primitifs ou d'objets:

  1. Pour les types primitifs, les paramètres sont pass-by-value
  2. Pour les types d'objet, la référence d'objet est passe-par-valeur

Les extraits de code utilisés dans cet article se trouvent à l'adresse over sur GitHub.