Quali argomenti passano per valore e quali passano per riferimento in Java?

5

Sto iniziando a imparare Java con i tutorial di Java Trails offerti da Oracle. Sono nella sezione in cui si parla del passaggio degli argomenti ai metodi Tutorial Java ™: passaggio di informazioni a un Metodo o un costruttore .

Si dice che i tipi primitivi vengono passati per valore, il che ha senso per me. Subito dopo dice:

Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object's fields can be changed in the method, if they have the proper access level.

Ora questo non ha senso per me. Se un oggetto viene passato per valore, la modifica dei campi di quell'oggetto cambierà i campi della copia all'interno del metodo, non quello originale.

Durante il test con il programma seguente:

class Point {
    int x;
    int y;

    public static void movePoint(Point p, int x, int y) {
        p.x+=x;
        p.y+=y;
    }
}
class App {
    public static void main(String argv[]) {
        Point p1;

        p1 = new Point();
        p1.x = 2;
        p1.y = 3;

        p1.movePoint(p1,2,2);

        System.out.println("x = " + p1.x +  " y = " + p1.y);
    }
}

Funzionava come se l'oggetto venisse passato per riferimento (dopo tutto, stampa x = 4 y = 5).

Quindi cosa significa esattamente Oracle nel passaggio sopra? Inoltre, qualcuno può riassumere cosa è passato per valore e cosa è passato per riferimento in Java?

    
posta Daniel Scocco 24.01.2012 - 19:10
fonte

2 risposte

6

Java è passato per valore. Consideralo come un linguaggio puntatore come C, il valore del puntatore (indirizzo di memoria) viene passato, quindi hai un riferimento allo stesso oggetto. I primitivi non sono archiviati internamente allo stesso modo degli oggetti, quindi quando passi il valore di un primitivo, è il contenuto, non un puntatore.

    
risposta data 24.01.2012 - 19:16
fonte
7

Esiste un test per stabilire se una lingua è pass-by-reference: puoi scrivere una funzione swap, in modo tale che dopo lo scambio (a, b), il chiamante scopre che i valori di a e b sono invertiti? Non puoi farlo in Java, nemmeno per gli oggetti.

Notare che non è possibile raggiungere questo obiettivo scambiando le parti interne dei due oggetti - mentre i dati possono cambiare, l'identità degli oggetti non ha, e questo ha delle conseguenze. Per prima cosa, qualsiasi altra variabile nel programma che ha fatto riferimento a entrambi gli oggetti vedrebbe anche la modifica.

Per capire perché non puoi scrivere questo swap, considera un modello semplificato del linguaggio, in cui il valore di una variabile di riferimento è l'indirizzo dell'oggetto a cui è attualmente associato (la garbage collection complica questa immagine in un modo non pertinente qui.) Prima della chiamata da scambiare, il frame dello stack del chiamante ha uno slot per a, contenente l'indirizzo dell'oggetto A, e uno slot per b contenente l'indirizzo di B. Quando lo swap viene chiamato, riceve i valori di aeb , che sono gli indirizzi di A e B rispettivamente. Pertanto, è disaccoppiato dal chiamante: non c'è semplicemente modo di trovare gli indirizzi degli slot per aeb all'interno del frame dello stack del chiamante, e quindi non c'è modo di impostarli in modo che il chiamante li vedrà scambiati. / p>

@supercat suggerisce un modo alternativo di guardarlo: concettualmente, una variabile di riferimento contiene l'ID univoco dell'oggetto a cui fa riferimento, qualcosa che è fissato per la vita dell'oggetto, ed è questo che viene copiato nella funzione in una chiamata. Questa vista chiarisce anche che la funzione non ha modo di trovare, e tanto meno di modificare, la variabile nel frame dello stack del chiamante.

Call-by-reference significa esattamente il contrario, per definizione: la funzione accede ai suoi argomenti attraverso i binding delle variabili del chiamante, in modo che cambiando uno dei suoi argomenti 'binding nella funzione necessariamente lo cambia nel frame dello stack del chiamante. Il termine risale a un tempo in cui le lingue mainstream non avevano oggetti o riferimenti come entità di prima classe e quando veniva passato un argomento, una copia del suo valore (in pass-by-value) o il suo indirizzo (in pass-by -referenza) è stato inserito nello stack in modo che la funzione potesse recuperarlo. Passare l'indirizzo di un argomento consente allo swap di funzionare, ma il passaggio di un indirizzo che contiene non lo è.

Un altro modo di guardarlo: pass-by-reference non significa passare il riferimento contenuto nella variabile argomento, significa creare, nella funzione, una variabile locale che fa riferimento alla variabile argomento.

Pertanto, possiamo vedere che Java usa il pass-by-value, non il riferimento pass-by.

Vedi anche Java è Pass-by-Value, Dammit! che discute anche il passaggio degli argomenti in Java RMI.

    
risposta data 10.04.2015 - 14:56
fonte

Leggi altre domande sui tag