methods or array - Java è "pass-by-reference" o "pass-by-value"?



15 Answers

Ho appena notato che hai fatto riferimento al mio articolo .

La specifica Java dice che tutto in Java è pass-by-value. Non esiste una cosa come "pass-by-reference" in Java.

La chiave per capire questo è qualcosa di simile

Dog myDog;

non è un cane; in realtà è un puntatore a un cane.

Cosa significa, è quando hai

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

stai essenzialmente passando l' indirizzo dell'oggetto Dog creato al metodo foo .

(Dico essenzialmente perché i puntatori Java non sono indirizzi diretti, ma è più facile pensarli in quel modo)

Supponiamo che l'oggetto Dog risieda all'indirizzo di memoria 42. Ciò significa che passiamo 42 al metodo.

se il metodo è stato definito come

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

diamo un'occhiata a cosa sta succedendo.

  • il parametro someDog è impostato sul valore 42
  • alla riga "AAA"
    • someDog è seguito al Dog cui punta (l'oggetto Dog all'indirizzo 42)
    • a quel Dog (quello all'indirizzo 42) viene chiesto di cambiare il suo nome in Max
  • alla riga "BBB"
    • viene creato un nuovo Dog Diciamo che è all'indirizzo 74
    • assegniamo il parametro someDog a 74
  • alla linea "CCC"
    • someDog è seguito al Dog cui punta (l'oggetto Dog all'indirizzo 74)
    • quel Dog (quello all'indirizzo 74) è invitato a cambiare il suo nome in Rowlf
  • poi, torniamo

Ora pensiamo a cosa succede al di fuori del metodo:

myDog cambiato?

C'è la chiave.

Tenendo presente che myDog è un puntatore e non un vero Dog , la risposta è NO. myDog ha ancora il valore 42; sta ancora puntando al Dog originale (ma nota che a causa della linea "AAA", il suo nome ora è "Max" - è ancora lo stesso Cane; il valore di myDog non è cambiato.)

È perfettamente valido seguire un indirizzo e cambiare ciò che è alla fine di esso; questo non cambia la variabile, comunque.

Java funziona esattamente come C. È possibile assegnare un puntatore, passare il puntatore a un metodo, seguire il puntatore nel metodo e modificare i dati puntati. Tuttavia, non puoi cambiare dove punta quel puntatore.

In C ++, Ada, Pascal e in altre lingue che supportano il pass-by-reference, puoi effettivamente cambiare la variabile che è stata passata.

Se Java avesse una semantica pass-by-reference, il metodo foo che abbiamo definito sopra sarebbe cambiato dove myDog stava puntando quando ha assegnato un someDog on line BBB.

Pensa ai parametri di riferimento come alias per la variabile passata. Quando viene assegnato quell'alias, lo è anche la variabile passata.

parameter copy object

Ho sempre pensato che Java fosse un riferimento pass-by .

Tuttavia, ho visto un paio di post del blog (ad esempio, questo blog ) che affermano che non lo è.

Non credo di capire la distinzione che stanno facendo.

Qual è la spiegazione?




Questo ti darà alcuni spunti su come Java funzioni davvero al punto che nella tua prossima discussione su Java che passa per riferimento o che passi per valore sorriderà :-)

Passo uno per favore cancella dalla tua mente quella parola che inizia con 'p' "_ _ _ _ _ _" ", specialmente se provieni da altri linguaggi di programmazione. Java e 'p' non possono essere scritti nello stesso libro, forum o anche txt.

La seconda fase ricorda che quando si passa un oggetto in un metodo si passa il riferimento all'oggetto e non l'oggetto stesso.

  • Studente : Master, significa che Java è pass-by-reference?
  • Maestro : cavalletta, n.

Ora pensa a che cosa fa / è un riferimento / variabile di un oggetto:

  1. Una variabile contiene i bit che indicano alla JVM come raggiungere l'oggetto di riferimento in memoria (Heap).
  2. Quando si passano argomenti a un metodo NON si sta passando la variabile di riferimento, ma una copia dei bit nella variabile di riferimento . Qualcosa del genere: 3bad086a. 3bad086a rappresenta un modo per arrivare all'oggetto passato.
  3. Quindi stai solo passando a 3bad086a che è il valore del riferimento.
  4. Stai passando il valore del riferimento e non il riferimento stesso (e non l'oggetto).
  5. Questo valore è in realtà COPIATO e dato al metodo .

Di seguito (per favore non provare a compilare / eseguire questo ...):

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. }

Che succede?

  • La persona variabile viene creata nella riga n. 1 ed è nulla all'inizio.
  • Un nuovo Oggetto Persona viene creato nella riga n. 2, memorizzato nella memoria e alla persona variabile viene assegnato il riferimento all'oggetto Persona. Cioè, il suo indirizzo. Diciamo 3bad086a.
  • La persona variabile che detiene l'indirizzo dell'oggetto viene passata alla funzione nella riga 3.
  • Alla riga 4 puoi ascoltare il suono del silenzio
  • Controlla il commento sulla linea # 5
  • Una variabile locale del metodo - anotherReferenceToTheSamePersonObject - viene creata e poi viene la magia nella riga n. 6:
    • La variabile / persona di riferimento viene copiata bit per bit e passata a anotherReferenceToTheSamePersonObject all'interno della funzione.
    • Non vengono create nuove istanze di Person.
    • Sia " persona " che " anotherReferenceToTheSamePersonObject " mantengono lo stesso valore di 3bad086a.
    • Non provare questo, ma person == anotherReferenceToTheSamePersonObject sarebbe vero.
    • Entrambe le variabili hanno COPIE IDENTICHE del riferimento e si riferiscono entrambi allo stesso oggetto Person, allo SAME Object sull'Heap e NON A COPY.

Un'immagine vale più di mille parole:

Nota che le frecce anotherReferenceToTheSamePersonObject sono dirette verso l'Oggetto e non verso la persona variabile!

Se non l'hai capito, fidati di me e ricorda che è meglio dire che Java è un valore . Bene, passa per valore di riferimento . Oh bene, ancora meglio è il valore della copia pass-by-the-variable! ;)

Ora sentitevi liberi di odiarmi, ma osservate che, dato ciò, non vi è alcuna differenza tra il passaggio di tipi di dati primitivi e Oggetti quando si parla di argomenti del metodo.

Si passa sempre una copia dei bit del valore del riferimento!

  • Se si tratta di un tipo di dati primitivo, questi bit conterranno il valore del tipo di dati primitivi stesso.
  • Se è un oggetto, i bit conterranno il valore dell'indirizzo che dice alla JVM come raggiungere l'oggetto.

Java è pass-by-value perché all'interno di un metodo puoi modificare l'oggetto di riferimento quanto vuoi ma non importa quanto duramente ci provi non sarai mai in grado di modificare la variabile passata che manterrà il riferimento (non p _ _ _ _ _ _ _) lo stesso oggetto, non importa cosa!

La funzione changeName precedente non sarà mai in grado di modificare il contenuto effettivo (i valori di bit) del riferimento passato. In altre parole changeName non può rendere Person persona riferirsi a un altro oggetto.

Ovviamente puoi tagliarlo brevemente e dire semplicemente che Java è un valore pass-by!




Java passa i riferimenti in base al valore.

Quindi non puoi cambiare il riferimento che viene passato.




Solo per mostrare il contrasto, confronta i seguenti frammenti C++ e Java :

In C ++: Nota: codice errato - perdite di memoria! Ma dimostra il punto.

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"
}

In 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 ha solo i due tipi di passaggio: per valore per i tipi predefiniti e per valore del puntatore per i tipi di oggetto.




Fondamentalmente, la riassegnazione dei parametri dell'oggetto non influisce sull'argomento, ad es.

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

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

stamperà "Hah!" invece di null . Il motivo per cui funziona è perché bar è una copia del valore di baz , che è solo un riferimento a "Hah!" . Se fosse il riferimento vero e proprio, allora foo avrebbe ridefinito il baz in null .




Il nocciolo della questione è che il riferimento alla parola nell'espressione "passa per riferimento" significa qualcosa di completamente diverso dal significato usuale della parola riferimento in Java.

Solitamente in riferimento Java indica un riferimento a un oggetto . Ma i termini tecnici passano per riferimento / valore dalla teoria del linguaggio di programmazione, si tratta di un riferimento alla cella di memoria che contiene la variabile , che è qualcosa di completamente diverso.




Un riferimento è sempre un valore quando rappresentato, indipendentemente dalla lingua che usi.

Ottenendo una vista al di fuori della finestra, diamo un'occhiata all'assemblaggio o ad una gestione della memoria di basso livello. A livello della CPU, un riferimento a qualsiasi cosa diventa immediatamente un valore se viene scritto nella memoria o in uno dei registri della CPU. (Ecco perché il puntatore è una buona definizione: è un valore, che ha uno scopo allo stesso tempo).

I dati in memoria hanno una Location e in quella posizione c'è un valore (byte, word, qualunque). In Assembly abbiamo una comoda soluzione per assegnare un Nome a una determinata posizione (variabile aka), ma quando si compila il codice, l'assemblatore semplicemente sostituisce Nome con la posizione designata, proprio come il browser sostituisce i nomi di dominio con gli indirizzi IP.

Giù fino al midollo è tecnicamente impossibile passare un riferimento a qualcosa in qualsiasi lingua senza rappresentarlo (quando diventa immediatamente un valore).

Diciamo che abbiamo una variabile Foo, la sua posizione è al 47 ° byte in memoria e il suo valore è 5. Abbiamo un'altra variabile Ref2Foo che è a 223rd byte in memoria, e il suo valore sarà 47. Questo Ref2Foo potrebbe essere una variabile tecnica , non creato esplicitamente dal programma. Se guardi solo 5 e 47 senza altre informazioni, vedrai solo due valori . Se li usi come riferimenti, allora per raggiungere 5dobbiamo viaggiare:

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

Ecco come funzionano i jump-tables.

Se vogliamo chiamare un metodo / funzione / procedura con il valore di Foo, ci sono alcuni modi possibili per passare la variabile al metodo, a seconda della lingua e delle sue diverse modalità di chiamata del metodo :

  1. 5 viene copiata in uno dei registri della CPU (ad esempio EAX).
  2. 5 ottiene PUSHd in pila.
  3. 47 viene copiata in uno dei registri della CPU
  4. 47 PUSH in pila.
  5. 223 viene copiata in uno dei registri della CPU.
  6. 223 ottiene PUSHd in pila.

In tutti i casi sopra i quali è stato creato un valore, una copia di un valore esistente, è ora disponibile il metodo di ricezione per gestirlo. Quando scrivi "Foo" all'interno del metodo, viene letto da EAX, o automaticamente dereferenziato , o dereferenziato, il processo dipende da come funziona la lingua e / o da quale tipo di Foo detta. Questo è nascosto allo sviluppatore fino a che non aggira il processo di dereferenziazione. Quindi un riferimento è un valore quando rappresentato, perché un riferimento è un valore che deve essere elaborato (a livello di lingua).

Ora abbiamo passato Foo al metodo:

  • nel caso 1. e 2. se si modifica Foo ( Foo = 9), questo ha effetto solo sull'ambito locale in quanto si ha una copia del Valore. Dall'interno del metodo non siamo nemmeno in grado di determinare in quale posizione si trovasse la Foo originale.
  • nel caso 3. e 4. se si usano costrutti di linguaggio predefiniti e si cambia Foo ( Foo = 11), potrebbe cambiare Foo globalmente (dipende dal linguaggio, ad esempio Java o come Pascal's procedure findMin(x, y, z: integer; var m : integer); ). Tuttavia, se il linguaggio consente di aggirare il processo di dereferenziamento, puoi cambiare 47, dillo a 49. A quel punto Foo sembra essere stato cambiato se lo hai letto, perché hai cambiato il puntatore locale ad esso. E se dovessi modificare questo Foo all'interno del metodo ( Foo = 12) probabilmente FUBAR eseguirai il programma (noto come segfault) perché scriverai su una memoria diversa da quella prevista, puoi anche modificare un'area che è destinata a contenere un eseguibile programma e la scrittura in esso modificherà il codice in esecuzione (Foo non è ora a 47). Ma il valore di Foo di47non è cambiato a livello globale, solo quello all'interno del metodo, perché 47era anche una copia del metodo.
  • nel caso 5. e 6. se si modifica 223all'interno del metodo si crea lo stesso caos come in 3. o 4. (un puntatore, che punta a un valore ora cattivo, che viene nuovamente utilizzato come puntatore) ma questo è ancora un locale problema, come 223 è stato copiato . Tuttavia se sei in grado di dereferenziare Ref2Foo(cioè 223), raggiungere e modificare il valore puntato 47, per esempio, 49influirà su Foo a livello globale , perché in questo caso i metodi hanno una copia di 223ma il riferimento 47esiste solo una volta e cambiando quello al 49porterà ogni Ref2Foodoppio dereferenziazione ad un valore errato.

Facendo clic su dettagli insignificanti, anche i linguaggi che passano per riferimento passano i valori alle funzioni, ma tali funzioni sanno che devono usarli per scopi di dereferenziazione. Questo pass-the-reference-as-value è appena nascosto dal programmatore perché è praticamente inutile e la terminologia è solo pass-by-reference .

Anche il pass-by-value rigoroso è inutile, significherebbe che un array da 100 Mbyte dovrebbe essere copiato ogni volta che chiamiamo un metodo con l'array come argomento, quindi Java non può essere strettamente pass-by-value. Ogni linguaggio passerebbe un riferimento a questo enorme array (come valore) e utilizza il meccanismo copy-on-write se tale array può essere modificato localmente all'interno del metodo o consente al metodo (come Java) di modificare l'array globalmente (da vista del chiamante) e alcune lingue consente di modificare il valore del riferimento stesso.

Quindi, in breve, e nella terminologia propria di Java, Java è un valore pass-by dove il valore può essere: un valore reale o un valore che è una rappresentazione di un riferimento .




Per quanto ne so, Java sa solo chiamare per valore. Questo significa che per i tipi di dati primitivi lavorerai con una copia e per gli oggetti lavorerai con una copia del riferimento agli oggetti. Comunque penso che ci siano alcune insidie; per esempio, questo non funzionerà:

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);
}

Questo popolerà Hello World e non World Hello perché nella funzione di swap si usano copys che non hanno alcun impatto sui riferimenti nel main. Ma se i tuoi oggetti non sono immutabili puoi cambiarli ad esempio:

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);
}

Questo popolerà Hello World sulla riga di comando. Se cambi StringBuffer in String, produrrà solo Hello perché String è immutabile. Per esempio:

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);
}

Comunque potresti creare un wrapper per String come questo che lo renderebbe in grado di usarlo con le stringhe:

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: credo che questo sia anche il motivo per usare StringBuffer quando si tratta di "aggiungere" due String perché è possibile modificare l'oggetto originale che non è possibile con oggetti immutabili come String.




Lasciatemi provare a spiegare la mia comprensione con l'aiuto di quattro esempi. Java è un valore pass-by e non un riferimento pass-by

/ **

Passa per valore

In Java, tutti i parametri vengono passati per valore, cioè l'assegnazione di un argomento metodo non è visibile al chiamante.

* /

Esempio 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";
    }
}

Risultato

output : output
value : Nikhil
valueflag : false

Esempio 2:

/ ** * * Passaggio per valore * * /

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";
    }
}

Risultato

output : output
value : Nikhil
valueflag : false

Esempio 3:

/ ** Questo 'Passaggio per valore ha la sensazione di' Passa per riferimento '

Alcuni dicono tipi primitivi e "String" sono "passano per valore" e gli oggetti sono "passano per riferimento".

Ma da questo esempio, possiamo capire che è effettivamente passato per valore, tenendo presente che qui stiamo passando il riferimento come valore. cioè: il riferimento è passato per valore. Questo è il motivo per cui sono in grado di cambiare e rimane vero dopo l'ambito locale. Ma non possiamo cambiare il riferimento reale al di fuori dell'ambito originale. ciò che significa è dimostrato dal prossimo esempio di 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";
    }
}

Risultato

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

Esempio 4:

/ **

Oltre a quanto menzionato nell'Esempio 3 (PassByValueObjectCase1.java), non possiamo modificare il riferimento effettivo al di fuori dell'ambito originale. "

Nota: non sto incollando il codice per private class Student. La definizione di classe per Studentè uguale a 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";
    }

}

Risultato

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



Java è una chiamata in base al valore.

Come funziona

  • Si passa sempre una copia dei bit del valore del riferimento!

  • Se si tratta di un tipo di dati primitivo, questi bit contengono il valore del tipo di dati primitivo stesso, ecco perché se cambiamo il valore dell'intestazione all'interno del metodo, allora non rifletterà le modifiche all'esterno.

  • Se si tratta di un tipo di dati oggetto come Foo foo = new Foo () allora in questo caso la copia dell'indirizzo dell'oggetto passa come una scorciatoia di file, supponiamo di avere un file di testo abc.txt in C: \ desktop e supponiamo di creare un collegamento di lo stesso file e lo metti all'interno di C: \ desktop \ abc-shortcut in modo tale che quando accedi al file da C: \ desktop \ abc.txt e scrivi '' e chiudi il file e di nuovo apri il file da scorciatoia scrivere "è la più grande comunità online per i programmatori da imparare", quindi il cambiamento totale dei file sarà " è la più grande comunità online per i programmatori da imparare"il che significa che non importa da dove apri il file, ogni volta che accedevamo allo stesso file, qui possiamo assumere Foo come file e supporre foo memorizzato a 123hd7h (indirizzo originale come C: \ desktop \ abc.txt ) indirizzo e 234jdid (indirizzo copiato come C: \ desktop \ abc-shortcut che in realtà contiene l'indirizzo originale del file all'interno). Quindi per una migliore comprensione, creare un file di collegamento e sentirsi ...




La distinzione, o forse solo il modo in cui mi ricordo come avevo una volta la stessa impressione del poster originale, è questa: Java è sempre un valore. Tutti gli oggetti (in Java, qualsiasi cosa tranne le primitive) in Java sono riferimenti. Questi riferimenti sono passati per valore.




Java ha passato solo per valore. Un esempio molto semplice per convalidare questo.

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();
}



Lo penso sempre come "passa per copia". È una copia del valore sia primitiva che di riferimento. Se è un primitivo è una copia dei bit che sono il valore e se è un oggetto è una copia del riferimento.

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;
    }
}

output di java PassByCopy:

nome = nome Maxx
= Fido

Le classi wrapper primitive e le stringhe sono immutabili, quindi qualsiasi esempio che utilizza quei tipi non funzionerà come altri tipi / oggetti.




Alcune correzioni ad alcuni post.

C NON supporta il passaggio per riferimento. È SEMPRE passare di valore. C ++ supporta pass per riferimento, ma non è il valore predefinito ed è piuttosto pericoloso.

Non importa quale sia il valore in Java: primitivo o indirizzo (grosso modo) dell'oggetto, esso viene SEMPRE passato per valore.

Se un oggetto Java "si comporta" come se fosse passato per riferimento, questa è una proprietà di mutabilità e non ha assolutamente nulla a che fare con i meccanismi di passaggio.

Non sono sicuro del perché questo sia così confuso, forse perché così tanti "programmatori" Java non sono formalmente addestrati e quindi non capiscono cosa sta realmente accadendo in memoria?




Java passa i parametri per VALUE e SOLO per valore .

Per farla breve:

Per quelli provenienti da C #: NON C'È alcun parametro "out".

Per chi proviene da PASCAL: NON C'È un parametro "var" .

Significa che non puoi cambiare il riferimento dall'oggetto stesso, ma puoi sempre modificare le proprietà dell'oggetto.

Una soluzione alternativa è utilizzare il StringBuilderparametro String. E puoi sempre usare gli array!




Related