passed - Java è "pass-by-reference" o "pass-by-value"?




object passed by reference java (20)

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 .

https://code.i-harness.com

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?


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 .


Java è sempre pass-by-value . Sfortunatamente, hanno deciso di chiamare la posizione di un oggetto come "riferimento". Quando passiamo il valore di un oggetto, stiamo passando il riferimento ad esso. Questo è fonte di confusione per i principianti.

Va così:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    // we pass the object to foo
    foo(aDog);
    // aDog variable is still pointing to the "Max" dog when foo(...) returns
    aDog.getName().equals("Max"); // true
    aDog.getName().equals("Fifi"); // false 
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // change d inside of foo() to point to a new Dog instance "Fifi"
    d = new Dog("Fifi");
    d.getName().equals("Fifi"); // true
}

Nell'esempio sopra aDog.getName() restituirà ancora "Max" . Il valore aDog all'interno di main non viene modificato nella funzione foo con Dog "Fifi" poiché il riferimento all'oggetto viene passato per valore. Se fosse passato per riferimento, allora aDog.getName() in main restituirebbe "Fifi" dopo la chiamata a foo .

Allo stesso modo:

public static void main(String[] args) {
    Dog aDog = new Dog("Max");
    foo(aDog);
    // when foo(...) returns, the name of the dog has been changed to "Fifi"
    aDog.getName().equals("Fifi"); // true
}

public static void foo(Dog d) {
    d.getName().equals("Max"); // true
    // this changes the name of d to be "Fifi"
    d.setName("Fifi");
}

Nell'esempio sopra, Fifi è il nome del cane dopo la chiamata a foo(aDog) perché il nome dell'oggetto è stato impostato all'interno di foo(...) . Tutte le operazioni che foo esegue su d sono tali che, per tutti gli scopi pratici, vengono eseguite su aDog stesso (tranne quando d viene modificato in modo da puntare a un'istanza Dog diversa come d = new Dog("Boxer") ).


Java passa i riferimenti agli oggetti in base al valore.


Java passa sempre argomenti per valore NON per riferimento.

Lasciatemi spiegare questo attraverso un example :

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

Lo spiegherò nei passaggi:

  1. Dichiarare un riferimento denominato f di tipo Foo e assegnarlo a un nuovo oggetto di tipo Foo con un attributo "f" .

    Foo f = new Foo("f");
    

  2. Dal lato del metodo, viene dichiarato un riferimento di tipo Foo con un nome a ed è inizialmente assegnato a null .

    public static void changeReference(Foo a)
    

  3. Quando chiami il metodo changeReference , il riferimento a verrà assegnato all'oggetto che viene passato come argomento.

    changeReference(f);
    

  4. Dichiarare un riferimento denominato b di tipo Foo e assegnarlo a un nuovo oggetto di tipo Foo con un attributo "b" .

    Foo b = new Foo("b");
    

  5. a = b sta riassegnando il riferimento a NOT f all'oggetto il cui attributo è "b" .

  6. Quando chiamate il modifyReference(Foo c) , viene creato un riferimento c viene assegnato all'oggetto con l'attributo "f" .

  7. c.setAttribute("c"); cambierà l'attributo dell'oggetto di riferimento c punta ad esso, ed è lo stesso oggetto a cui fa riferimento f .

Spero che tu capisca ora come funzionano gli oggetti come oggetti in Java :)


Java passa sempre per valore, senza eccezioni, mai .

Quindi, come mai qualcuno può essere affatto confuso da questo, e credere che Java sia passato per riferimento, o pensa di avere un esempio di Java che agisce come passaggio per riferimento? Il punto chiave è che Java non fornisce mai l'accesso diretto ai valori degli oggetti stessi , in nessuna circostanza. L'unico accesso agli oggetti è attraverso un riferimento a quell'oggetto. Poiché gli oggetti Java sono sempre accessibili attraverso un riferimento, piuttosto che direttamente, è comune parlare di campi e variabili e argomenti del metodo come oggetti , quando pedanticamente sono solo riferimenti agli oggetti . La confusione deriva da questo (rigorosamente, errato) cambiamento nella nomenclatura.

Quindi, quando si chiama un metodo

  • Per gli argomenti primitivi ( int , long , ecc.), Il valore passa per valore è il valore reale della primitiva (ad esempio, 3).
  • Per gli oggetti, il passaggio per valore è il valore del riferimento all'oggetto .

Quindi se hai doSomething(foo) e public void doSomething(Foo foo) { .. } i due Foos hanno copiato riferimenti che puntano agli stessi oggetti.

Naturalmente, passando per valore, un riferimento ad un oggetto assomiglia molto (ed è indistinguibile in pratica da) che passa un oggetto per riferimento.


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.


In Java vengono passati solo riferimenti e vengono passati per valore:

Gli argomenti Java vengono tutti passati per valore (il riferimento viene copiato quando viene utilizzato dal metodo):

Nel caso di tipi primitivi, il comportamento di Java è semplice: il valore viene copiato in un'altra istanza del tipo primitivo.

In caso di oggetti, questo è lo stesso: le variabili oggetto sono puntatori (bucket) che contengono solo l' indirizzo dell'oggetto che è stato creato utilizzando la parola chiave "new" e vengono copiati come tipi primitivi.

Il comportamento può apparire diverso dai tipi primitivi: poiché la variabile oggetto copiata contiene lo stesso indirizzo (allo stesso oggetto), il contenuto / i membri dell'oggetto potrebbero ancora essere modificati all'interno di un metodo e successivamente l'accesso all'esterno, dando l'illusione che l'oggetto (contenente) è stato passato per riferimento.

Gli oggetti "a stringa" sembrano essere un perfetto contro-esempio alla leggenda metropolitana dicendo che "Gli oggetti vengono passati per riferimento":

In effetti, all'interno di un metodo che non sarai mai in grado di aggiornare il valore di una stringa passata come argomento:

Un oggetto String, contiene i caratteri di un array dichiarato finale che non può essere modificato. Solo l'indirizzo dell'oggetto può essere sostituito da un altro utilizzando "nuovo". L'utilizzo di "new" per aggiornare la variabile, non consentirà l'accesso all'oggetto dall'esterno, poiché la variabile è stata inizialmente passata per valore e copiata.


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!


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


No, non è passato per riferimento.

Java è passato per valore in base alla specifica del linguaggio Java:

Quando viene invocato il metodo o il costruttore (§15.12), i valori delle espressioni degli argomenti effettivi inizializzano le variabili dei parametri appena create , ciascuno del tipo dichiarato, prima dell'esecuzione del corpo del metodo o del costruttore. L'identificatore che appare nel DeclaratorId può essere usato come un nome semplice nel corpo del metodo o costruttore per fare riferimento al parametro formale .


Ho creato una discussione dedicata a questo tipo di domande per tutti i linguaggi di programmazione here .

Viene anche menzionato Java . Ecco il breve riassunto:

  • Java passa i parametri in base al valore
  • "by value" è l'unico modo in java per passare un parametro ad un metodo
  • l'utilizzo di metodi dall'oggetto fornito come parametro modificherà l'oggetto come i riferimenti puntano agli oggetti originali. (se quel metodo stesso altera alcuni valori)

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.


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

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!


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]

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.


Non si può mai passare per riferimento in Java e uno dei modi ovvi è quando si desidera restituire più di un valore da una chiamata di metodo. Considera il seguente bit di codice in C ++:

void getValues(int& arg1, int& arg2) {
    arg1 = 1;
    arg2 = 2;
}
void caller() {
    int x;
    int y;
    getValues(x, y);
    cout << "Result: " << x << " " << y << endl;
}

A volte vuoi usare lo stesso pattern in Java, ma non puoi; almeno non direttamente. Invece si potrebbe fare qualcosa di simile:

void getValues(int[] arg1, int[] arg2) {
    arg1[0] = 1;
    arg2[0] = 2;
}
void caller() {
    int[] x = new int[1];
    int[] y = new int[1];
    getValues(x, y);
    System.out.println("Result: " + x[0] + " " + y[0]);
}

Come è stato spiegato nelle risposte precedenti, in Java stai passando un puntatore all'array come valore in getValues. Questo è sufficiente, perché il metodo quindi modifica l'elemento dell'array e, per convenzione, ti aspetti che l'elemento 0 contenga il valore restituito. Ovviamente puoi farlo in altri modi, come la strutturazione del tuo codice, quindi questo non è necessario o la costruzione di una classe che può contenere il valore restituito o consentirne l'impostazione. Ma il semplice schema disponibile in C ++ sopra non è disponibile in Java.


Per farla breve, gli oggetti Java hanno alcune proprietà molto peculiari.

In generale, Java ha tipi primitivi ( int, bool, char, double, ecc) che sono passati direttamente per valore. Quindi Java ha oggetti (tutto ciò che deriva da java.lang.Object). Gli oggetti sono in realtà sempre gestiti attraverso un riferimento (un riferimento è un puntatore che non puoi toccare). Ciò significa che, in effetti, gli oggetti vengono passati per riferimento, in quanto i riferimenti normalmente non sono interessanti. Significa tuttavia che non è possibile modificare a quale oggetto viene indirizzato, in quanto il riferimento stesso viene passato per valore.

Questo suona strano e confuso? Consideriamo come le implementazioni C passano per riferimento e passano per valore. In C, la convenzione di default è passata per valore. void foo(int x)passa un int in base al valore. void foo(int *x)è una funzione che non vuole una int a, ma un puntatore ad un int: foo(&a). Uno userebbe questo con l' &operatore per passare un indirizzo variabile.

Prendi questo in C ++ e abbiamo riferimenti. I riferimenti sono fondamentalmente (in questo contesto) zucchero sintattico che nasconde la parte puntatore dell'equazione: void foo(int &x)è chiamata da foo(a), dove il compilatore stesso sa che è un riferimento e l'indirizzo del non riferimento adeve essere passato. In Java, tutte le variabili che fanno riferimento agli oggetti sono in realtà di tipo di riferimento, in effetti obbligano la chiamata per riferimento per la maggior parte degli scopi e finalità senza il controllo (e la complessità) fornito da, ad esempio, C ++.





pass-by-value