Kann ich Parameter in Java als Referenz übergeben?


Antworten:


225

Java ist verwirrend, weil alles als Wert übergeben wird . Für einen Parameter vom Referenztyp (dh keinen Parameter vom primitiven Typ) ist es jedoch die Referenz selbst, die als Wert übergeben wird, daher scheint es sich um eine Referenzübergabe zu handeln (und die Leute behaupten oft, dass dies der Fall ist). Dies ist nicht der Fall, wie Folgendes zeigt:

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

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

Wird Helloauf der Konsole gedruckt . Wenn Sie möchten, dass der obige Code gedruckt Goodbyewird, verwenden Sie eine explizite Referenz wie folgt:

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
Außerdem kann ein Array der Länge 1 verwendet werden, um eine Referenz zu erstellen, wenn Sie die Leute wirklich verwirren möchten :)
Christoffer

2
AtomicReference und entsprechende Klassen (AtomicInteger) eignen sich am besten für solche Operationen
Naveen

3
AtomicReference ist ein Overkill, Sie wollen dort nicht unbedingt eine Speicherbarriere, und sie könnten Sie kosten. JRuby hatte ein Leistungsproblem aufgrund einer flüchtigen Variablen, die beim Erstellen eines Objekts verwendet wurde. Die Option, Array als Ad-hoc-Referenz zu verwenden, scheint mir gut genug zu sein, und ich habe gesehen, dass es mehr als einmal verwendet wurde.
Elazar Leibovich

Ich denke nicht, dass dies verwirrend ist, dies ist jedoch ein normales Verhalten. Werttypen existieren auf dem Stapel und Referenztypen existieren auf dem Heap, aber Verweise auf Referenztypen existieren auch auf dem Stapel. Sie arbeiten also immer mit dem Wert, der sich auf dem Stapel befindet. Ich glaube, die Frage hier war: Ist es möglich, eine Referenz vom Stapel zu übergeben, die auf einen anderen Wert verweist, der sich ebenfalls auf dem Stapel befindet? Oder eine Referenz einer anderen Referenz übergeben, die auf einen Wert verweist, der auf einem Haufen lebt?
Eomeroff

das ich tolle info. Ich hatte Arrays verwendet, aber dies scheint etwas für den Job gebaut zu sein. Ich weiß nicht über die Leistung dieses Arrays im
Vergleich zu

65

Kann ich Parameter in Java als Referenz übergeben?

Nein.

Warum ? Java hat nur einen Modus zum Übergeben von Argumenten an Methoden: nach Wert.

Hinweis:

Für Grundelemente ist dies leicht zu verstehen: Sie erhalten eine Kopie des Werts.

Für alle anderen erhalten Sie eine Kopie der Referenz, die auch als Wertübergabe bezeichnet wird.

Es ist alles auf diesem Bild:

Geben Sie hier die Bildbeschreibung ein


25

In Java gibt es auf Sprachebene nichts Vergleichbares wie ref . In Java wird nur die Wertesemantik übergeben

Aus Neugier können Sie eine ref-ähnliche Semantik in Java implementieren, indem Sie Ihre Objekte einfach in eine veränderbare Klasse einschließen:

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

Testfall:

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

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

Warum nicht stattdessen java.lang.ref.Reference verwenden?
Hardcoded

java.lang.ref.Reference hat keine festgelegte Methode, sie ist nicht veränderbar
dfa

warum nicht verwenden AtomicReference(für Nicht-Primitive)? Oder AtomicSomething(zB :) AtomicBooleanfür Primitive?
Arvin

Leider akzeptiert <T> keine primitiven Typen. Möchte dies tun: Ref <int>
jk7

1
@ jk7 Ist es wirklich wichtig genug, intstatt Integer, boolstatt Booleanund so weiter verwenden zu müssen? Das heißt, Wrapper-Klassen (die automatisch entpackt werden, wenn Sie sich Gedanken über die Syntax machen) funktionieren nicht?
Paul Stelian

18

Von James Gosling in "The Java Programming Language":

"... In Java gibt es genau einen Parameterübergabemodus - Übergabe nach Wert - und das hält die Dinge einfach. ..."


2
Die Aussprache des Sprachgottes sollte zur Antwort erklärt werden.
Ingyhere

3
@ingyhere :: The pronouncement of the language god should be declared the answerNicht wirklich. Ungeachtet dessen, was der Schöpfer von Java denkt oder glaubt, würde die absolute Antwort aus einem Zitat aus der Sprachspezifikation stammen.
Paercebal

1
In der Tat ist es in den JLS, in Abschnitt 8.4.1 und die JLS zitiert Gosling als erster Autor: „Wenn das Verfahren oder der Konstruktor aufgerufen wird (§15.12) Initialisieren der Werte der Ist - Argument Ausdrücke neu Parametervariablen erstellt , von denen jede vom deklarierten Typ vor der Ausführung des Hauptteils der Methode oder des Konstruktors. "
Ingyhere

Genau. Sarkasmus von Mitgliedern mit geringen Wiederholungszahlen ist nicht hilfreich.
Duffymo

11

Ich glaube nicht, dass du kannst. Ihre beste Option könnte darin bestehen, das Objekt, das Sie "by ref" an eine andere Klasseninstanz übergeben möchten, zu kapseln und die Referenz der (äußeren) Klasse (nach Wert) zu übergeben. Wenn du verstehst was ich meine...

Das heißt, Ihre Methode ändert den internen Status des übergebenen Objekts, das dann für den Aufrufer sichtbar ist.


7

Java wird immer als Wert übergeben.

Wenn Sie ein Grundelement übergeben, ist es eine Kopie des Werts. Wenn Sie ein Objekt übergeben, ist es eine Kopie des Referenzzeigers.


4

Eine andere Möglichkeit ist die Verwendung eines Arrays, z. B. void method(SomeClass[] v) { v[0] = ...; } 1) das Array muss vor dem Aufrufen der Methode initialisiert werden, 2) man kann zB die Swap-Methode noch nicht auf diese Weise implementieren ... Diese Art wird in JDK verwendet, z java.util.concurrent.atomic.AtomicMarkableReference.get(boolean[]). B. in .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.