methods passage par - Java est-il «passe-à-référence» ou «passe-à-valeur»?





15 Answers

Je viens de remarquer que vous avez référencé mon article .

La spécification Java indique que tout en Java est transmis valeur par valeur. "Pass-by-reference" n'existe pas en Java.

La clé pour comprendre cela est que quelque chose comme

Dog myDog;

n'est pas un chien; c'est en fait un pointeur sur un chien.

Qu'est-ce que cela signifie, c'est quand vous avez

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

vous passez essentiellement l' adresse de l'objet Dog créé à la méthode foo .

(Je dis essentiellement parce que les pointeurs Java ne sont pas des adresses directes, mais il est plus facile de les penser ainsi)

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

si la méthode était définie 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 a la valeur 42
  • à la ligne "AAA"
    • someDog est suivi jusqu'au Dog someDog (l'objet Dog à l'adresse 42)
    • ce Dog (celui à l'adresse 42) est invité à changer son nom en Max
  • à la ligne "BBB"
    • un nouveau Dog est créé. Disons qu'il est à l'adresse 74
    • on assigne le paramètre someDog à 74
  • à la ligne "CCC"
    • someDog est suivi jusqu'au Dog indiqué (l'objet Dog à l'adresse 74)
    • ce Dog (celui à l'adresse 74) est invité à changer son nom en Rowlf
  • alors, nous revenons

Maintenant réfléchissons à ce qui se passe en dehors de la méthode:

myDog t- myDog changé?

Il y a la clé.

En gardant à l'esprit que myDog est un pointeur et non un Dog , la réponse est NON. myDog toujours la valeur 42; il pointe toujours vers le Dog origine (mais notez qu'à cause de la ligne "AAA", son nom est maintenant "Max" - toujours le même chien; la valeur de myDog n'a pas changé.)

Il est parfaitement valable de suivre une adresse et de changer ce qui se trouve à la fin. cela ne change pas la variable, cependant.

Java fonctionne exactement comme le point C. Vous pouvez affecter un pointeur, le transmettre à une méthode, suivre le pointeur de la méthode et modifier les données pointées. Cependant, vous ne pouvez pas modifier le pointeur.

En C ++, Ada, Pascal et d'autres langages prenant en charge la référence par référence, vous pouvez réellement modifier la variable transmise.

Si Java avait une sémantique de référence par référence, la méthode foo nous avons définie ci-dessus aurait changé à l'endroit myDog lorsqu'il avait assigné someDog à la ligne BBB.

Considérez les paramètres de référence comme des alias pour la variable transmise. Lorsque cet alias est attribué, il en va de même pour la variable transmise.

int exemple string

J'ai toujours pensé que Java était passe-à-référence .

Cependant, j'ai vu quelques articles de blog (par exemple, ce blog ) affirmer que ce n'est pas le cas.

Je ne pense pas comprendre la distinction qu'ils font.

Quelle est l'explication?




Cela vous donnera un aperçu du fonctionnement de Java au point que lors de votre prochaine discussion sur le passage de Java par référence ou par valeur, vous sourirez :-)

La première étape, effacez de votre esprit ce mot qui commence par 'p' "_ _ _ _ _ _ _ _", surtout si vous venez d'autres langages de programmation. Java et 'p' ne peuvent pas être écrits dans le même livre, forum ou même txt.

La deuxième étape consiste à rappeler que lorsque vous transmettez un objet à une méthode, vous transmettez la référence à l'objet et non l'objet lui-même.

  • Étudiant : Maître, cela signifie-t-il que Java est un référentiel?
  • Master : Sauterelle, Non.

Maintenant, pensons à ce que la référence / variable d’un objet fait / est:

  1. Une variable contient les bits qui indiquent à la machine virtuelle Java comment accéder à l'objet référencé en mémoire (tas).
  2. Lorsque vous transmettez des arguments à une méthode, vous ne transmettez PAS la variable de référence, mais une copie des bits de la variable de référence . Quelque chose comme ça: 3bad086a. 3bad086a représente un moyen d'obtenir l'objet passé.
  3. Donc, vous dites simplement à 3bad086a que c'est la valeur de la référence.
  4. Vous transmettez la valeur de la référence et non la référence elle-même (et non l'objet).
  5. Cette valeur est réellement COPIED et attribuée à la méthode .

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

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 produit?

  • La variable personne est créée dans la ligne n ° 1 et elle est nulle au début.
  • Un nouvel objet Personne est créé à la ligne 2, stocké en mémoire et la personne variable reçoit la référence à l'objet Personne. C'est son adresse. Disons 3bad086a.
  • La variable personne détenant l'adresse de l'objet est transmise à la fonction de la ligne 3.
  • En ligne 4, vous pouvez écouter le son du silence
  • Voir le commentaire à la ligne 5
  • Une variable locale de méthode - anotherReferenceToTheSamePersonObject - est créée puis la magie à la ligne 6:
    • La variable / personne de référence est copiée bit par bit et transmise à anotherReferenceToTheSamePersonObject dans la fonction.
    • Aucune nouvelle instance de Personne n'est créée.
    • " Person " et " anotherReferenceToTheSamePersonObject " ont la même valeur, 3bad086a.
    • N'essayez pas ceci, mais personne == autreReferenceToTheSamePersonObject serait vrai.
    • Les deux variables ont une copie IDENTICAL COPIES de la référence et font référence au même objet Personne, à l'objet SAME sur le tas et à PAS UNE COPIE.

Une image vaut mieux que mille mots:

Notez que les flèches anotherReferenceToTheSamePersonObject sont dirigées vers l'objet et non vers la personne variable!

Si vous ne l'obtenez pas, faites-moi confiance et rappelez-vous qu'il est préférable de dire que Java est réputé valeur par passe . Eh bien, passez par la valeur de référence . Oh, eh bien, le mieux est de passer par copie de la valeur variable! ;)

Maintenant, sentez-vous libre de me détester, mais sachez qu’il n’ya aucune différence entre le passage de types de données primitifs et d’objets lorsqu’on parle d’arguments de méthode.

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

  • S'il s'agit d'un type de données primitif, ces bits contiendront la valeur du type de données primitif lui-même.
  • S'il s'agit d'un objet, les bits contiendront la valeur de l'adresse indiquant à la machine virtuelle Java comment se rendre à l'objet.

Java est passe-par-valeur car, dans une méthode, vous pouvez modifier l’objet référencé autant de fois que vous le souhaitez, mais vous ne pourrez jamais modifier la variable transmise qui gardera le référencement référé (pas p _ _ _ _ _ _ _) le même objet, peu importe quoi!

La fonction changeName ci-dessus ne pourra jamais modifier le contenu réel (les valeurs en bits) de la référence transmise. En d'autres termes, changeName ne peut pas faire référence à un autre objet.

Bien sûr, vous pouvez couper court et simplement dire que Java est une valeur ajoutée!




Java transmet les références par valeur.

Donc, vous ne pouvez pas changer la référence qui est transmise.




Juste pour montrer le contraste, comparez les extraits de code C++ et Java :

En C ++: Remarque: Code incorrect - Fuites de mémoire! Mais cela démontre le point.

void cppMethod(int val, int &ref, Dog obj, Dog &objRef, Dog *objPtr, Dog *&objPtrRef)
{
    val = 7; // Modifies the copy
    ref = 7; // Modifies the original variable
    obj.SetName("obj"); // Modifies the copy of Dog passed
    objRef.SetName("objRef"); // Modifies the original Dog passed
    objPtr->SetName("objPtr"); // Modifies the original Dog pointed to 
                               // by the copy of the pointer passed.
    objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                   // leaving the original object alone.
    objPtrRef->SetName("objRefPtr"); // Modifies the original Dog pointed to 
                                    // by the original pointer passed. 
    objPtrRef = new Dog("newObjPtrRef"); // Modifies the original pointer passed
}

int main()
{
    int a = 0;
    int b = 0;
    Dog d0 = Dog("d0");
    Dog d1 = Dog("d1");
    Dog *d2 = new Dog("d2");
    Dog *d3 = new Dog("d3");
    cppMethod(a, b, d0, d1, d2, d3);
    // a is still set to 0
    // b is now set to 7
    // d0 still have name "d0"
    // d1 now has name "objRef"
    // d2 now has name "objPtr"
    // d3 now has name "newObjPtrRef"
}

En Java,

public static void javaMethod(int val, Dog objPtr)
{
   val = 7; // Modifies the copy
   objPtr.SetName("objPtr") // Modifies the original Dog pointed to 
                            // by the copy of the pointer passed.
   objPtr = new Dog("newObjPtr");  // Modifies the copy of the pointer, 
                                  // leaving the original object alone.
}

public static void main()
{
    int a = 0;
    Dog d0 = new Dog("d0");
    javaMethod(a, d0);
    // a is still set to 0
    // d0 now has name "objPtr"
}

Java ne dispose que des deux types de transmission: par valeur pour les types intégrés et par valeur du pointeur pour les types d'objet.




En gros, la réaffectation des paramètres d'objet n'affecte pas l'argument, par exemple,

private void foo(Object bar) {
    bar = null;
}

public static void main(String[] args) {
    String baz = "Hah!";
    foo(baz);
    System.out.println(baz);
}

imprimera au "Hah!"lieu de null. La raison pour laquelle cela fonctionne est parce que barest une copie de la valeur de baz, qui est juste une référence à"Hah!" .Si elle était la référence elle - même, puis fooaurait redéfini bazà null.




Le noeud du problème est que le mot référence dans l'expression "passer par référence" signifie quelque chose de complètement différent du sens habituel du mot référence en Java.

Habituellement, en Java, référence signifie une référence à un objet . Mais les termes techniques transmis par référence / valeur de la théorie des langages de programmation parlent d'une référence à la cellule de mémoire contenant la variable , ce qui est complètement différent.




Une référence est toujours une valeur lorsqu'elle est représentée, quelle que soit la langue utilisée.

Pour obtenir une vue en dehors de la boîte, examinons Assembly ou une gestion de mémoire de bas niveau. Au niveau de la CPU, une référence à n'importe quoi devient immédiatement une valeur si elle est écrite dans la mémoire ou dans l'un des registres de la CPU. (C’est pourquoi le pointeur est une bonne définition. C’est une valeur qui a un but en même temps).

Les données en mémoire ont un emplacement et à cet emplacement une valeur (octet, mot, peu importe). Dans Assembly, nous avons une solution pratique pour attribuer un nom à un certain emplacement (variable), mais lors de la compilation du code, l'assembleur remplace simplement Nom par l'emplacement désigné, tout comme votre navigateur remplace les noms de domaine par des adresses IP.

Au fond, il est techniquement impossible de faire référence à quoi que ce soit dans n'importe quelle langue sans la représenter (quand cela devient immédiatement une valeur).

Disons que nous avons une variable Foo, son emplacement est à l'octet 47e dans la mémoire et sa valeur est 5. Nous avons une autre variable Ref2Foo qui est à l' octet 223e en mémoire, et sa valeur sera 47. Ce Ref2Foo pourrait être une variable technique , pas explicitement créé par le programme. Si vous ne regardez que 5 et 47 sans autre information, vous ne verrez que deux valeurs . Si vous les utilisez comme références, 5vous devez voyager:

(Name)[Location] -> [Value at the Location]
---------------------
(Ref2Foo)[223]  -> 47
(Foo)[47]       -> 5

Voici comment fonctionnent les tables de saut.

Si nous voulons appeler une méthode / fonction / procédure ayant la valeur de Foo, il existe plusieurs façons de transmettre la variable à la méthode, en fonction du langage et de ses différents modes d'appel de méthode:

  1. 5 est copié dans l’un des registres de la CPU (c’est-à-dire EAX).
  2. 5 obtient PUSHd à la pile.
  3. 47 est copié dans l'un des registres de la CPU
  4. 47 PUSH à la pile.
  5. 223 est copié dans l’un des registres de la CPU.
  6. 223 obtient PUSHd à la pile.

Dans tous les cas, au-dessus d'une valeur - une copie d'une valeur existante - a été créée, il appartient maintenant à la méthode de réception de la gérer. Lorsque vous écrivez "Foo" dans la méthode, celle-ci est lue à partir de EAX, ou automatiquement déréférencée ou dupliquée, le processus dépend de la façon dont la langue fonctionne et / ou du type de dictée de Foo. Ceci est caché du développeur jusqu'à ce qu'il contourne le processus de déréférencement. Ainsi, une référence est une valeur lorsqu'elle est représentée, car une référence est une valeur qui doit être traitée (au niveau de la langue).

Maintenant nous avons passé Foo à la méthode:

  • dans les cas 1. et 2. si vous modifiez Foo ( Foo = 9), cela n'affecte que la portée locale car vous avez une copie de la valeur. De l'intérieur de la méthode, nous ne pouvons même pas déterminer où se trouvait le Foo original en mémoire.
  • dans les cas 3. et 4. si vous utilisez des constructions de langage par défaut et changez Foo ( Foo = 11), cela pourrait changer Foo globalement (dépend du langage, c'est-à-dire Java ou le procedure findMin(x, y, z: integer; var m de Pascal : integer);). Toutefois, si le langage vous permet de contourner le processus de déréférence, vous pouvez changer 47, dites à 49. À ce stade, Foo semble avoir été modifié si vous le lisez, car vous avez changé le pointeur local . Et si vous deviez modifier ce Foo à l'intérieur de la méthode ( Foo = 12), vous fuberez probablement l'exécution du programme (alias. Segfault) car vous écrirez dans une mémoire différente de celle attendue, vous pouvez même modifier une zone destinée à contenir des exécutables. le programme et l’écriture modifieront le code courant (Foo n’est plus maintenant 47). MAIS la valeur de Foo47n'a pas changé globalement, seulement celui à l'intérieur de la méthode, car 47était également une copie de la méthode.
  • dans les cas 5. et 6. si vous modifiez 223dans la méthode, cela crée le même chaos que dans 3. ou 4. (un pointeur, pointant sur une valeur désormais incorrecte, qui est à nouveau utilisé comme pointeur), mais il s'agit toujours d'un paramètre local. problème, car 223 a été copié . Cependant, si vous êtes capable de déréférencer Ref2Foo(c'est-à-dire 223), d'atteindre et de modifier la valeur pointée 47, par exemple, 49cela affectera Foo globalement , car dans ce cas, les méthodes ont une copie de 223mais le référencé 47n'existe qu'une seule fois, à 49conduire chaque Ref2Foodouble-déréférencement à une mauvaise valeur.

Si vous sélectionnez des détails insignifiants, même les langues qui passent par référence transmettent des valeurs aux fonctions, mais ces fonctions savent qu'elles doivent l'utiliser à des fins de déréférencement. Cette valeur de référence de référence est simplement masquée pour le programmeur car elle est pratiquement inutile et la terminologie n’est que transmission par référence .

Une valeur de passe par valeur stricte est également inutile, cela signifierait qu'un tableau de 100 Mo devrait être copié chaque fois que nous appelons une méthode avec le tableau en argument, par conséquent, Java ne peut pas être strictement passé par valeur. Chaque langue passera une référence à cet énorme tableau (en tant que valeur) et utilisera le mécanisme de copie sur écriture si ce tableau peut être modifié localement dans la méthode ou autorise la méthode (comme le fait Java) à modifier le tableau globalement (de la vue de l'appelant) et quelques langues permettent de modifier la valeur de la référence elle-même.

En bref, et dans la terminologie propre à Java, Java est une valeur donnéevaleur peut être: une valeur réelle ou une valeur représentant une référence .




Autant que je sache, Java ne connaît que l'appel par la valeur. Cela signifie que pour les types de données primitifs, vous utiliserez une copie et pour les objets, vous utiliserez une copie de la référence aux objets. Cependant, je pense qu'il y a des pièges; par exemple, cela ne fonctionnera pas:

public static void swap(StringBuffer s1, StringBuffer s2) {
    StringBuffer temp = s1;
    s1 = s2;
    s2 = temp;
}


public static void main(String[] args) {
    StringBuffer s1 = new StringBuffer("Hello");
    StringBuffer s2 = new StringBuffer("World");
    swap(s1, s2);
    System.out.println(s1);
    System.out.println(s2);
}

Ceci peuplera Hello World et non World Hello car dans la fonction swap, vous utilisez des copies qui n’ont aucune incidence sur les références. Mais si vos objets ne sont pas immuables, vous pouvez le changer par exemple:

public static void appendWorld(StringBuffer s1) {
    s1.append(" World");
}

public static void main(String[] args) {
    StringBuffer s = new StringBuffer("Hello");
    appendWorld(s);
    System.out.println(s);
}

Ceci peuplera Hello World en ligne de commande. Si vous modifiez StringBuffer en String, il produira uniquement Hello car String est immuable. Par exemple:

public static void appendWorld(String s){
    s = s+" World";
}

public static void main(String[] args) {
    String s = new String("Hello");
    appendWorld(s);
    System.out.println(s);
}

Cependant, vous pouvez créer un wrapper pour String comme celui-ci, ce qui le permettrait de l'utiliser avec Strings:

class StringWrapper {
    public String value;

    public StringWrapper(String value) {
        this.value = value;
    }
}

public static void appendWorld(StringWrapper s){
    s.value = s.value +" World";
}

public static void main(String[] args) {
    StringWrapper s = new StringWrapper("Hello");
    appendWorld(s);
    System.out.println(s.value);
}

edit: Je crois que c’est aussi la raison pour laquelle StringBuffer est utilisé pour "ajouter" deux chaînes car vous pouvez modifier l’objet original, ce qui ne peut pas être fait avec des objets immuables comme String.




Laissez-moi essayer d’expliquer ma compréhension à l’aide de quatre exemples. Java est passe-par-valeur et non pas par référence

/ **

Pass par valeur

En Java, tous les paramètres sont passés par valeur, c'est-à-dire que l'affectation d'un argument de méthode n'est pas visible pour l'appelant.

* /

Exemple 1:

public class PassByValueString {
    public static void main(String[] args) {
        new PassByValueString().caller();
    }

    public void caller() {
        String value = "Nikhil";
        boolean valueflag = false;
        String output = method(value, valueflag);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'value' and 'valueflag'
         */
        System.out.println("output : " + output);
        System.out.println("value : " + value);
        System.out.println("valueflag : " + valueflag);

    }

    public String method(String value, boolean valueflag) {
        value = "Anand";
        valueflag = true;
        return "output";
    }
}

Résultat

output : output
value : Nikhil
valueflag : false

Exemple 2:

/ ** * * Pass By Value * * /

public class PassByValueNewString {
    public static void main(String[] args) {
        new PassByValueNewString().caller();
    }

    public void caller() {
        String value = new String("Nikhil");
        boolean valueflag = false;
        String output = method(value, valueflag);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'value' and 'valueflag'
         */
        System.out.println("output : " + output);
        System.out.println("value : " + value);
        System.out.println("valueflag : " + valueflag);

    }

    public String method(String value, boolean valueflag) {
        value = "Anand";
        valueflag = true;
        return "output";
    }
}

Résultat

output : output
value : Nikhil
valueflag : false

Exemple 3:

/ ** Ce 'Pass By Value a le sentiment de' Pass By Reference '

Certaines personnes disent que les types primitifs et 'String' sont 'pass by value' et les objets sont 'pass by reference'.

Mais à partir de cet exemple, nous pouvons comprendre qu’il s’agit en fait de transmettre uniquement par valeur, en gardant à l’esprit que nous transmettons ici la référence en tant que valeur. ie: la référence est passée par valeur. C'est pourquoi sont capables de changer et cela reste vrai après la portée locale. Mais nous ne pouvons pas modifier la référence réelle en dehors de la portée d'origine. ce que cela signifie est illustré par l'exemple suivant de PassByValueObjectCase2.

* /

public class PassByValueObjectCase1 {

    private class Student {
        int id;
        String name;
        public Student() {
        }
        public Student(int id, String name) {
            super();
            this.id = id;
            this.name = name;
        }
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Student [id=" + id + ", name=" + name + "]";
        }
    }

    public static void main(String[] args) {
        new PassByValueObjectCase1().caller();
    }

    public void caller() {
        Student student = new Student(10, "Nikhil");
        String output = method(student);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'student'
         */
        System.out.println("output : " + output);
        System.out.println("student : " + student);
    }

    public String method(Student student) {
        student.setName("Anand");
        return "output";
    }
}

Résultat

output : output
student : Student [id=10, name=Anand]

Exemple 4:

/ **

En plus de ce qui a été mentionné dans Example3 (PassByValueObjectCase1.java), nous ne pouvons pas modifier la référence réelle en dehors de la portée d'origine. "

Remarque: je ne colle pas le code pour private class Student. La définition de classe pour Studentest identique à Example3.

* /

public class PassByValueObjectCase2 {

    public static void main(String[] args) {
        new PassByValueObjectCase2().caller();
    }

    public void caller() {
        // student has the actual reference to a Student object created
        // can we change this actual reference outside the local scope? Let's see
        Student student = new Student(10, "Nikhil");
        String output = method(student);
        /*
         * 'output' is insignificant in this example. we are more interested in
         * 'student'
         */
        System.out.println("output : " + output);
        System.out.println("student : " + student); // Will it print Nikhil or Anand?
    }

    public String method(Student student) {
        student = new Student(20, "Anand");
        return "output";
    }

}

Résultat

output : output
student : Student [id=10, name=Nikhil]



Java est un appel par valeur.

Comment ça marche

  • Vous transmettez toujours une copie des bits de la valeur de la référence!

  • S'il s'agit d'un type de données primitif, ces bits contiennent la valeur du type de données primitif lui-même. C'est pourquoi, si nous modifions la valeur de l'en-tête dans la méthode, elle ne reflète pas les modifications apportées à l'extérieur.

  • S'il s'agit d'un type de données d'objet tel que Foo foo = new Foo (), dans ce cas, la copie de l'adresse de l'objet passe comme un raccourci de fichier, supposons que nous ayons un fichier texte abc.txt sur C: \ desktop et supposons que nous faisons un raccourci de le même fichier et le mettre à l'intérieur de C: \ desktop \ abc-raccourci, donc lorsque vous accédez au fichier à partir de C: \ desktop \ abc.txt et écrivez '' , fermez le fichier et ouvrez de nouveau le fichier à partir du raccourci. write "est la plus grande communauté en ligne pour les programmeurs à apprendre", puis le changement total de fichier sera " est la plus grande communauté en ligne pour les programmeurs à apprendre"ce qui signifie que peu importe d'où vous ouvrez le fichier, chaque fois que nous accédons au même fichier, nous pouvons supposer ici que Foo est un fichier et supposons que foo est stocké à 123hd7h (adresse d'origine telle que C: \ desktop \ abc.txt ) address et 234jdid (adresse copiée telle que C: \ desktop \ abc-shortcut qui contient en fait l'adresse d'origine du fichier à l'intérieur). Alors, pour une meilleure compréhension, créez un fichier de raccourci et ressentez ...




La distinction, ou peut-être juste la façon dont je me souviens car j’avais la même impression que l’affiche originale est la suivante: Java est toujours transmis par valeur. Tous les objets (en Java, tout sauf les primitives) en Java sont des références. Ces références sont passées par valeur.




Java a seulement passer par valeur. Un exemple très simple pour valider cela.

public void test() {
    MyClass obj = null;
    init(obj);
    //After calling init method, obj still points to null
    //this is because obj is passed as value and not as reference.
}
private void init(MyClass objVar) {
    objVar = new MyClass();
}



Je pense toujours à cela comme "passe par copie". C'est une copie de la valeur, que ce soit une primitive ou une référence. S'il s'agit d'une primitive, il s'agit d'une copie des bits correspondant à la valeur. S'il s'agit d'un objet, il s'agit d'une copie de la référence.

public class PassByCopy{
    public static void changeName(Dog d){
        d.name = "Fido";
    }
    public static void main(String[] args){
        Dog d = new Dog("Maxx");
        System.out.println("name= "+ d.name);
        changeName(d);
        System.out.println("name= "+ d.name);
    }
}
class Dog{
    public String name;
    public Dog(String s){
        this.name = s;
    }
}

sortie de java PassByCopy:

nom = Maxx
nom = Fido

Les classes et les chaînes de wrapper primitives étant immuables, aucun exemple utilisant ces types ne fonctionnera de la même manière que d'autres types / objets.




Quelques corrections à quelques articles.

C ne prend PAS en charge le passage par référence. C'est TOUJOURS passer par valeur. C ++ supporte passe par référence, mais n'est pas la valeur par défaut et est assez dangereux.

Peu importe la valeur en Java: primitive ou adresse (approximativement) d'objet, elle est TOUJOURS passée par valeur.

Si un objet Java "se comporte" comme s'il était passé par référence, il s'agit d'une propriété de mutabilité qui n'a absolument rien à voir avec les mécanismes de passage.

Je ne sais pas pourquoi cela est si déroutant, peut-être parce que tant de "programmeurs" Java ne sont pas formellement formés et ne comprennent donc pas ce qui se passe réellement en mémoire?




Java transmet les paramètres par valeur et uniquement par valeur .

Pour résumer l'histoire courte:

Pour ceux qui viennent de C #: IL N'Y A PAS de paramètre "out".

Pour ceux qui viennent de PASCAL: IL N'Y A PAS de paramètre "var" .

Cela signifie que vous ne pouvez pas modifier la référence de l'objet lui-même, mais vous pouvez toujours modifier les propriétés de l'objet.

Une solution de contournement consiste à utiliser le StringBuilderparamètre à la place String. Et vous pouvez toujours utiliser des tableaux!






Related