Duplicata possible: Est Java passe par référence?
public class myClass{
public static void main(String[] args){
myObject obj = new myObject("myName");
changeName(obj);
System.out.print(obj.getName()); // This prints "anotherName"
}
public static void changeName(myObject obj){
obj.setName("anotherName");
}
}
Je sais que Java passe par valeur, mais pourquoi passe-t-il obj
par référence dans l'exemple précédent et le change-t-il?
Java passe toujours les arguments par valeur, PAS par référence. Dans votre exemple, vous passez toujours obj
par sa valeur, pas la référence elle-même. Dans votre méthode changeName
, vous assignez une autre référence (locale), obj
, au même objet que vous l'avez passé en argument. Une fois que vous avez modifié cette référence, vous modifiez la référence d'origine, obj
, qui est passée en argument.
MODIFIER:
Permettez-moi d'expliquer cela à travers un exemple:
public class Main
{
public static void main(String[] args)
{
Foo f = new Foo("f");
changeReference(f); // It won't change the reference!
modifyReference(f); // It will change the object that the reference refers to!
}
public static void changeReference(Foo a)
{
Foo b = new Foo("b");
a = b;
}
public static void modifyReference(Foo c)
{
c.setAttribute("c");
}
}
Je vais l'expliquer par étapes:
1- Déclarer une référence nommée f
de type Foo
et l'affecter à un nouvel objet de type Foo
avec un attribut "f"
.
Foo f = new Foo("f");
2- Du côté méthode, une référence de type Foo
avec un nom a
est déclarée et elle est initialement affectée à null
.
public static void changeReference(Foo a)
3- Lorsque vous appelez la méthode changeReference
, la référence a
sera affectée à l'objet qui est passé en argument.
changeReference(f);
4- Déclarer une référence nommée b
de type Foo
et l'affecter à un nouvel objet de type Foo
avec un attribut "b"
.
Foo b = new Foo("b");
5- a = b
Réattribue la référence a
PAS f
à l'objet dont son attribut est "b"
.
6- Lorsque vous appelez la méthode modifyReference(Foo c)
, une référence c
est créée et affectée à l'objet avec l'attribut "f"
.
7- c.setAttribute("c");
changera l'attribut de l'objet qui référence c
pointe vers lui, et c'est le même objet qui référence f
pointe vers lui.
J'espère que vous comprenez maintenant comment fonctionne le passage d'objets comme arguments dans Java :)
En Java, un descripteur d'objet ou l'identité d'un objet est considéré comme une valeur. Passer par la valeur signifie passer cette poignée, pas une copie complète de l'objet.
Une "référence" dans le terme "passer par référence" ne signifie pas non plus "référence à un objet". Cela signifie "référence à une variable" - un "compartiment" nommé dans une définition de fonction (ou, plutôt, un cadre d'appel) qui peut stocker une valeur.
Passer par référence signifierait que la méthode appelée pourrait changer valeurs variables dans la méthode appelante. (Par exemple, dans la bibliothèque standard C, la fonction scanf
fonctionne de cette façon.) Ce n'est pas possible en Java. Vous pouvez toujours changer les propriétés d'un objet - ils ne sont pas considérés comme faisant partie de sa "valeur". Ce sont des objets indépendants complètement différents.
Vous modifiez une propriété de obj
, et non pas obj
(le paramètre) lui-même.
Le fait est que si vous avez pointé obj
vers autre chose dans changeName
que ce changement ne serait pas reflété dans main
.
Voir cet article pour plus de précisions.
Il n'a pas changé d'obj (votre code ne le change pas de toute façon). S'il avait été adopté par référence, vous auriez pu écrire:
public static void changeName(myObject obj){
obj = new myObject("anotherName");
}
Et faites imprimer "anotherName" par la méthode principale.
Java transmet une copie de ce que vous transmettez à votre fonction. Lorsqu'il s'agit d'un type primitif - ce sera la copie d'une valeur. Quand c'est un objet - vous passez la copie de référence. Dans votre exemple de code, vous modifiez l'une des propriétés des objets, mais pas la référence elle-même, donc le nom sera changé. Cependant, lorsque vous souhaitez affecter un nouvel objet à la variable obj dans la fonction changeName, vous modifiez la référence, donc obj extérieur aura une ancienne valeur.
C'est passer la référence à obj comme valeur (un peu déroutant je sais :)).
Disons donc qu'il fait une copie du pointeur sur la valeur d'obj et transmettons cela.
Cela signifie que vous pouvez faire des choses comme:
public static void changeName(myObject obj){
obj.setName("anotherName");
obj = new myObject();
}
et la déclaration
System.out.print(obj.getName());
va toujours faire référence à l'ancien objet (celui que vous avez défini setName).