Posso passare i parametri per riferimento in Java?


Risposte:


225

Java è confuso perché tutto viene passato per valore . Tuttavia per un parametro di tipo di riferimento (cioè non un parametro di tipo primitivo) è il riferimento stesso che viene passato per valore, quindi sembra essere pass-by-reference (e le persone spesso affermano che lo sia). Questo non è il caso, come mostrato dal seguente:

Object o = "Hello";
mutate(o)
System.out.println(o);

private void mutate(Object o) { o = "Goodbye"; } //NOT THE SAME o!

Stampa Hellosulla console. Le opzioni se si desidera stampare il codice sopra Goodbyesono di utilizzare un riferimento esplicito come segue:

AtomicReference<Object> ref = new AtomicReference<Object>("Hello");
mutate(ref);
System.out.println(ref.get()); //Goodbye!

private void mutate(AtomicReference<Object> ref) { ref.set("Goodbye"); }

48
Inoltre, puoi creare un array di lunghezza 1 per creare un riferimento se vuoi davvero confondere le persone :)
Christoffer

2
AtomicReference e le classi corrispondenti (AtomicInteger) sono le migliori per tali operazioni
Naveen,

3
AtomicReference è un problema eccessivo, non necessariamente la barriera di memoria è lì e potrebbero costarti. JRuby ha avuto problemi di perfomance a causa di una variabile volatile utilizzata durante la costruzione di un oggetto. L'opzione di usare l'array come riferimento ad hoc mi sembra abbastanza buona e l'ho vista usata più di una volta.
Elazar Leibovich,

Non penso che ciò sia fonte di confusione, tuttavia si tratta di un comportamento normale. I tipi di valore esistono nello stack e i tipi di riferimento esistono nell'heap, ma i riferimenti ai tipi di riferimento esistono anche nello stack. In questo modo si opera sempre con un valore nello stack. Credo che la domanda qui fosse: è possibile passare un riferimento dallo stack che punta su un altro valore che è anche sullo stack. O passare il riferimento di un altro riferimento che punta su un valore che vive nell'heap?
Eomeroff,

questa sono un'ottima informazione. stavo usando array ma questo sembra qualcosa di costruito per il lavoro. non so delle prestazioni di questo vs. array, tuttavia, se in un ciclo critico per le prestazioni
steveh

65

Posso passare i parametri per riferimento in Java?

No.

Perché ? Java ha solo una modalità per passare argomenti ai metodi: per valore.

Nota:

Per le primitive questo è facile da capire: ottieni una copia del valore.

Per tutti gli altri si ottiene una copia del riferimento e questo si chiama anche passando per valore.

È tutto in questa immagine:

inserisci qui la descrizione dell'immagine


25

In Java non esiste nulla a livello di linguaggio simile a ref . In Java c'è solo un passaggio per valore semantico

Per motivi di curiosità puoi implementare una semantica ref-like in Java semplicemente avvolgendo i tuoi oggetti in una classe mutabile:

public class Ref<T> {

    private T value;

    public Ref(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }

    public void set(T anotherValue) {
        value = anotherValue;
    }

    @Override
    public String toString() {
        return value.toString();
    }

    @Override
    public boolean equals(Object obj) {
        return value.equals(obj);
    }

    @Override
    public int hashCode() {
        return value.hashCode();
    }
}

TestCase:

public void changeRef(Ref<String> ref) {
    ref.set("bbb");
}

// ...
Ref<String> ref = new Ref<String>("aaa");
changeRef(ref);
System.out.println(ref); // prints "bbb"

Perché non usare java.lang.ref.Reference invece?
Hardcoded,

java.lang.ref.Reference non ha un metodo impostato, non è mutabile
dfa

perché non usare AtomicReference(per i non primitivi)? O AtomicSomething(es . AtomicBoolean:) per i primitivi?
Arvin,

Sfortunatamente, <T> non accetta tipi primitivi. Vorrei fare questo: Ref <int>
jk7

1
@ jk7 È davvero importante usare intinvece di Integer, boolinvece di Booleane così via? Cioè, le classi wrapper (che vengono automaticamente scartate se ti preoccupi della sintassi) non funzionano?
Paul Stelian,

18

Da James Gosling in "Il linguaggio di programmazione Java":

"... Esiste esattamente un modo di passare parametri in Java - passa per valore - e questo semplifica le cose ..."


2
La pronuncia del dio della lingua dovrebbe essere dichiarata la risposta.
ingyhere

3
@ingyhere:: The pronouncement of the language god should be declared the answernon proprio. Nonostante ciò che il creatore di Java pensa o crede, la risposta assoluta verrebbe da una citazione dalle specifiche del linguaggio.
paercebal,

1
In effetti è nel JLS, nella sezione 8.4.1 , e il JLS cita Gosling come primo autore: "Quando viene invocato il metodo o il costruttore (§15.12), i valori delle espressioni degli argomenti effettivi inizializzano le variabili dei parametri appena create , ciascuna del tipo dichiarato, prima dell'esecuzione del corpo del metodo o del costruttore. "
inghehere

Esattamente. Il sarcasmo da parte di membri con bassa reputazione non è utile.
duffymo,

11

Non penso che tu possa. La tua migliore opzione potrebbe essere quella di incapsulare la cosa che vuoi passare "per ref" in un'altra istanza di classe e passare il riferimento della classe (esterna) (per valore). Se vedi cosa intendo ...

cioè il tuo metodo cambia lo stato interno dell'oggetto che viene passato, che è quindi visibile al chiamante.


7

Java è sempre passato per valore.

Quando passi una primitiva è una copia del valore, quando passi un oggetto è una copia del puntatore di riferimento.


4

Un'altra opzione è quella di utilizzare un array, ad esempio void method(SomeClass[] v) { v[0] = ...; } ma 1) l'array deve essere inizializzato prima che il metodo venga invocato, 2) ancora non è possibile implementare ad esempio il metodo di scambio in questo modo ... Questo modo è usato in JDK, ad esempio in java.util.concurrent.atomic.AtomicMarkableReference.get(boolean[]).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.