6318 votes

Est Java "par référence" ou de "passage par valeur"?

J'ai toujours pensé que Java était passé par référence; mais j'ai vu quelques posts (par exemple, ce blog) qui affirment qu'elle ne l'est pas. Je ne pense pas que je comprends la distinction qu'ils font.

Quelle est l'explication?

5631voto

erlando Points 5802

Java est toujours passé par valeur. La difficulté peut être de comprendre que Java passe les objets comme des références et ces références sont passés par valeur.

Il va comme ceci:

Dog aDog = new Dog("Max");
foo(aDog);
aDog.getName().equals("Max"); // true

public void foo(Dog d) {
  d.getName().equals("Max"); // true
  d = new Dog("Fifi");
  d.getName().equals("Fifi"); // true
}

Dans cet exemple, aDog.getName() retournera toujours "Max". d n'est pas remplacé dans la fonction de l'objet de référence est passé par valeur.

De la même manière:

Dog aDog = new Dog("Max");
foo(aDog);
aDog.getName().equals("Fifi"); // true

public void foo(Dog d) {
  d.getName().equals("Max"); // true
  d.setName("Fifi");
}

2961voto

Scott Stanchfield Points 15863

Je viens de remarquer que vous l'avez mentionné dans mon article ;)

La Java Spec dit que tout dans Java est passé par valeur. Il n'y a pas une telle chose comme "par référence" en Java.

La clé pour comprendre c'est que quelque chose comme

Dog myDog;

est pas un Chien; c'est en fait un pointeur à un Chien.

Ce que cela signifie, c'est quand vous avez

Dog myDog = new Dog("Rover");
foo(myDog);

vous êtes essentiellement en passant l' adresse de l'créée Dog objet à l' foo méthode.

(Je dis essentiellement parce que Java pointeurs ne sont pas les adresses directes, mais il est plus facile de penser de cette façon)

Supposons que l' Dog objet se trouve à l'adresse mémoire 42. Cela signifie que nous passons 42 de la méthode.

si la Méthode ont été définis comme

public void foo(Dog someDog) {
    someDog.setName("Max");     // AAA
    someDog = new Dog("Fifi");  // BBB
    someDog.setName("Rowlf");   // CCC
}

regardons ce qui se passe.

  • le paramètre someDog la valeur 42
  • à la ligne "AAA"
    • someDog est suivie à l' Dog il pointe vers ( Dog objet à l'adresse 42)
    • qu' Dog (l'un à l'adresse 42) est demandé de changer son nom de Max
  • à la ligne "BBB"
    • un nouveau Dog est créé. Disons qu'il est à l'adresse 74
    • nous affecter le paramètre someDog à 74
  • à la ligne "CCC"
    • someDog est suivie à l' Dog il pointe vers ( Dog objet à l'adresse 74)
    • qu' Dog (l'un à l'adresse 74) est demandé de changer son nom pour Rowlf
  • ensuite, nous reviendrons

Maintenant, nous allons réfléchir sur ce qui se passe en dehors de la méthode:

Avez - myDog changement?

Il y a la clé.

En gardant à l'esprit qu' myDog est un pointeur, et pas un Dog, la réponse est NON. myDog a encore de la valeur 42; il est toujours en pointant à la version originale Dog.

Il est parfaitement valide pour suivre une adresse et de changer ce qui est à la fin de celui-ci; cela ne change pas la variable, cependant.

Java fonctionne exactement comme le C. Vous pouvez affecter un pointeur, passer le pointeur à une méthode, suivez le pointeur de la méthode et de modifier les données qui a été souligné. Cependant, vous ne pouvez pas modifier l'endroit où le pointeur de points.

En C++, Ada, Pascal et d'autres langues que le soutien par référence, vous pouvez réellement changer la variable qui a été adoptée.

Si Java avait passé par référence sémantique, l' foo méthode que nous avons définie ci-dessus aurait changé où myDog pointait quand il a assigné someDog sur la ligne de BBB.

Pensez à des paramètres de référence comme alias de la variable passée dans. Lorsque cet alias est attribué, est donc la variable qui a été passé.

Est-ce que c'est? (Je vais ajouter ce que un addendum à mon article...)
-- Scott

1663voto

Eng.Fouad Points 44085

Java passe toujours des arguments par valeur et NON par référence.


Laissez-moi vous expliquer cela par 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 modify the object that the reference variable "f" 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 vous expliquer cela en plusieurs étapes:

  1. La déclaration d'une référence nommée f de type Foo et l'attribuer à un nouvel objet de type Foo avec un attribut "f".

    Foo f = new Foo("f");
    

    enter image description here

  2. À partir de la méthode de côté, une référence de type Foo avec un nom a est déclaré et il est d'abord affecté à l' null.

    public static void changeReference(Foo a)
    

    enter image description here

  3. Comme vous l'appelez la méthode changeReference, la référence a seront affectés à l'objet qui est passé comme un argument.

    changeReference(f);
    

    enter image description here

  4. La déclaration d'une référence nommée b de type Foo et l'attribuer à un nouvel objet de type Foo avec un attribut "b".

    Foo b = new Foo("b");
    

    enter image description here

  5. a = b re-affectation de la référence a PAS f pour l'objet dont son attribut est - "b".

    enter image description here


  6. Comme vous l'appelez modifyReference(Foo c) méthode, une référence c est créée et affectée à l'objet avec l'attribut "f".

    enter image description here

  7. c.setAttribute("c"); va changer l'attribut de l'objet de référence c de points à elle, et c'est même l'objet de référence f des points.

    enter image description here

J'espère que vous comprenez maintenant comment le passage d'objets comme arguments fonctionne en Java :)

717voto

Gevorg Points 4218

Cela vous donnera un aperçu de la façon dont Java fonctionne vraiment, au point que, lors de votre prochaine discussion à propos de Java, le passage par référence ou passage par valeur, vous aurez juste sourire :-)

L'étape une, merci de l'effacer de votre esprit un mot qui commence par "p' "_ _ _ _ _ _ _", surtout si vous venez d'autres langages de programmation. Java et 'p' ne peut pas être écrit dans le même livre, forum, ou même txt.

Étape deux souvenez-vous que lorsque vous transmettez un Objet dans une méthode que vous êtes en passant la référence de l'Objet et non l'Objet lui-même.

  • Étudiant: Maître, est-ce à dire que Java est passé par référence?
  • Maître: Sauterelle, Pas.

Maintenant, pensez à ce qu'est une référence de l'Objet/variable ne/est:

  1. Une variable contient les bits qui indiquent la JVM comment arriver à l'Objet référencé dans la mémoire (Heap).
  2. Lors du passage d'arguments à une méthode vous n'ÊTES PAS en passant la variable de référence, mais une copie des bits de la variable de référence. Quelque chose comme ceci: 3bad086a. 3bad086a représente un moyen d'obtenir de l'objet passé.
  3. Si vous êtes juste de passage 3bad086a que c'est la valeur de la référence.
  4. Vous êtes de passage de la valeur de la référence, et non la référence elle-même (et non pas de l'objet).
  5. Cette valeur est COPIÉE et compte tenu de la méthode.

Dans ce qui suit (merci de ne pas essayer de compiler/exécuter cette...):

1. Person person;
2. person = new Person("Tom");
3. changeName(person);
4.
5. //I didn't use Person person below as an argument to be nice
6. static void changeName(Person anotherReferenceToTheSamePersonObject) {
7.     anotherReferenceToTheSamePersonObject.setName("Jerry");
8. }

Ce qui se passe?

  • La variable personne est créée dans la ligne #1 et c'est nul au début.
  • Un nouvel Objet est créé dans la ligne #2, stockées dans la mémoire, et la variable d'une personne est donné la référence de l'objet Personne. C'est, à son adresse. Disons 3bad086a.
  • La variable personne tenant l'adresse de l'Objet est passé à la fonction en ligne #3.
  • Dans la ligne #4 vous pouvez écouter le son du silence
  • Vérifiez le commentaire sur la ligne n ° 5
  • Une méthode de variable locale -anotherReferenceToTheSamePersonObject- est créé, puis vient la magie en ligne n ° 6:
    • La variable de référence/ personne est copié bit-par-bit et passé à anotherReferenceToTheSamePersonObject l'intérieur de la fonction.
    • Aucun nouveau cas de la Personne sont créés.
    • Les deux "personne" et "anotherReferenceToTheSamePersonObject" contenir la même valeur de 3bad086a.
    • N'essayez pas de cela, mais personne==anotherReferenceToTheSamePersonObject serait vrai.
    • Les deux variables ont des COPIES IDENTIQUES de la référence et tous deux se réfèrent à la même Personne, l'Objet, le MÊME Objet sur le Tas et NON UNE COPIE.

Une image vaut mille mots:

Pass by Value

Notez que le anotherReferenceToTheSamePersonObject flèches est dirigé vers l'Objet et non pas vers la variable personne!

Si vous ne l'avez pas alors fais-moi confiance et n'oubliez pas que c'est mieux de dire que Java est le passage par valeur. Eh bien, passe par la valeur de référence. Eh bien, même mieux, c'est de passer par-copie-de-la-variable-valeur! ;)

Maintenant n'hésitez pas à me détester, mais note que, compte tenu de cela il n'y a pas de différence entre la réussite des types de données primitifs et des Objets lorsque l'on parle des arguments de méthode.

Vous passez toujours une copie de bits de la valeur de la référence!

  • Si c'est un type de données primitif de ces bits contenant la valeur du type de données primitif lui-même.
  • Si c'est un Objet les bits contenant la valeur de l'adresse, qui raconte la JVM comment faire pour obtenir l'Objet.

Java est passé par valeur, car à l'intérieur d'une méthode, vous pouvez modifier l'Objet référencé autant que vous voulez mais pas n'importe comment dur vous essayez, vous ne serez jamais en mesure de modifier le passé de la variable qui va garder le référencement (pas de p _ _ _ _ _ _ _) le même Objet, n'importe quoi!


Le changeName fonction ci-dessus ne seront jamais en mesure de modifier le contenu réel (les valeurs des bits) de la référence. En d'autres mots changeName ne peut pas faire de Personne à personne de référence à un autre Objet.


Bien sûr, vous pouvez couper court et juste dire que Java est passé par valeur!

662voto

SCdF Points 11397

Java est toujours le passage par valeur, sans exception, jamais.

Alors, comment est-ce que quelqu'un peut être à tout confus par cela, et de croire que Java est passer par référence, ou pensent qu'ils ont un exemple de Java agissant en tant que passage par référence? Le point clé est que Java ne jamais offre un accès direct aux valeurs des objets eux-mêmes, dans toutes les circonstances. Le seul accès aux objets est par le biais d'une référence à cet objet. Parce que les objets Java sont toujours accessibles via une référence, plutôt que directement, il est courant de parler de champs et variables et arguments de méthode comme étant des objets, lorsqu'manière affectée ils ne sont que des références à des objets. La confusion vient de ce (strictement parlant, incorrect) changement de nomenclature.

Ainsi, lors de l'appel d'une méthode

  • Pour les arguments primitifs (int, long, etc.), le passage par valeur est la valeur réelle de la primitive (par exemple, 3).
  • Pour les objets, le passage par valeur est la valeur de la référence à l'objet.

Donc, si vous avez doSomething(foo) et public void doSomething(Foo foo) { .. } les deux Foos avez copié les références qui pointent vers le même objet.

Naturellement, en passant par la valeur d'une référence à un objet ressemble beaucoup (impossible de distinguer dans la pratique) de passage d'un objet par référence.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X