7750 Stimmen

Ist Java "per Referenz übergeben" oder "per Wert übergeben"?

Ich habe immer gedacht, dass Java call-by-reference verwendet. Allerdings habe ich einen Blog-Beitrag gelesen, der behauptet, dass Java call-by-value verwendet. Ich glaube, ich verstehe nicht, welche Unterscheidung der Autor macht.

Was ist die Erklärung?

6 Stimmen

Wir würden eher sagen, dass eine Variable, die "per Referenz übergeben" wird, verändert werden kann. Der Begriff taucht in Lehrbüchern auf, weil Sprachtheoretiker eine Möglichkeit brauchten, um zu unterscheiden, wie Sie primitive Datentypen (int, bool, byte) von komplexen und strukturierten Objekten (Array, Streams, Klasse) behandeln - das heißt, die möglicherweise ungebundene Speicherzuweisung.

6 Stimmen

Ich möchte darauf hinweisen, dass Sie sich in den meisten Fällen keine Gedanken darüber machen müssen. Ich habe viele Jahre lang Java programmiert, bis ich C ++ gelernt habe. Bis zu diesem Zeitpunkt hatte ich keine Ahnung, was Übergabe nach Referenz und Übergabe nach Wert sind. Die intuitive Lösung hat immer für mich funktioniert, deshalb ist Java eine der besten Sprachen für Anfänger. Wenn Sie sich also gerade Sorgen machen, ob Ihre Funktion eine Referenz oder einen Wert benötigt, übergeben Sie sie einfach so, wie sie ist, und es wird alles in Ordnung sein.

73 Stimmen

Java übergibt die Referenz nach Wert.

393voto

ScArcher2 Punkte 81775

Java übergibt Verweise nach Wert.

Das bedeutet, dass Sie den übergebenen Verweis nicht ändern können.

0 Stimmen

Wirft die Frage auf, ob Java eine objektorientierte oder referenzorientierte Sprache ist, anstatt "ein Mechanismus zum Übergeben von Argumenten". de.wikipedia.org/wiki/Java_(Programmiersprache)#Prinzipien

0 Stimmen

Was für eine schöne und prägnante Erklärung.

299voto

cutmancometh Punkte 1627

Ich denke, dass es nicht wirklich hilfreich ist, über Übergabe per Referenz vs. Übergabe per Wert zu streiten.

Wenn du sagst, dass Java übergibt-wie-auch-immer ist, gibst du keine vollständige Antwort. Hier sind einige zusätzliche Informationen, die hoffentlich helfen zu verstehen, was tatsächlich im Speicher passiert.

Kurzer Kurs über Stack/Heap, bevor wir zur Java-Implementierung kommen: Werte kommen ordentlich auf den Stack und gehen wieder runter, wie ein Stapel Teller in einer Cafeteria. Speicher im Heap (auch bekannt als dynamischer Speicher) ist chaotisch und unorganisiert. Die JVM findet einfach Platz, wo sie kann, und gibt ihn frei, wenn die Variablen, die ihn benutzen, nicht mehr benötigt werden.

Also. Lokale Primitiven kommen auf den Stack. Also wird dieser Code:

int x = 3;
float y = 101.1f;
boolean binIchToll = true;

zu diesem Ergebnis führen:

Primitiven auf dem Stack

Wenn du ein Objekt deklarierst und instanziierst, dann geht das tatsächliche Objekt auf den Heap. Was kommt auf den Stack? Die Adresse des Objekts auf dem Heap. C++-Programmierer würden dies als Zeiger bezeichnen, aber einige Java-Entwickler sind gegen das Wort "Zeiger". Wie auch immer. Wisse nur, dass die Adresse des Objekts auf dem Stack liegt.

So:

int probleme = 99;
String name = "Jay-Z";

ein Problem weniger!

Ein Array ist auch ein Objekt, also geht es auch auf den Heap. Und was ist mit den Objekten im Array? Sie bekommen ihren eigenen Heap-Speicher, und die Adresse jedes Objekts wird im Array gespeichert.

JButton[] marxBros = new JButton[3];
marxBros[0] = new JButton("Groucho");
marxBros[1] = new JButton("Zeppo");
marxBros[2] = new JButton("Harpo");

Marx-Brothers

Also, was wird übergeben, wenn du eine Methode aufrufst? Wenn du ein Objekt übergibst, dann übergibst du tatsächlich die Adresse des Objekts. Einige würden sagen, der "Wert" der Adresse, und einige sagen, es ist nur eine Referenz auf das Objekt. Dies ist der Ursprung des heiligen Krieges zwischen den Vertretern von "Referenz" und "Wert". Wie auch immer du es nennst, wichtig ist nur, dass du verstehst, dass die Adresse des Objekts übergeben wird.

private static void rufen(String name){
    System.out.println("Da geht " + name + "!");
}

public static void main(String[] args){
    String seinName = "John J. Jingleheimerschmitz";
    String meinName = seinName;
    rufen(meinName);
}

Ein String wird erstellt und Speicherplatz dafür auf dem Heap reserviert, und die Adresse des Strings wird auf dem Stack gespeichert und mit dem Bezeichner seinName versehen. Da die Adresse des zweiten Strings die gleiche wie die des ersten ist, wird kein neuer String erstellt und kein neuer Heap-Speicher reserviert, aber ein neuer Bezeichner wird auf dem Stack erstellt. Dann rufen wir rufen(): ein neuer Stackrahmen wird erstellt und ein neuer Bezeichner, name, wird erstellt und der bereits vorhandene String zugewiesen.

La da di da da da da

Also, Wert, Referenz? Du sagst "Kartoffel".

12 Stimmen

Eine so großartige Antwort, dass selbst ein Narr wie ich es verstanden hat. Ich würde hinzufügen, dass "pass by value" wörtlich bedeutet, dass der buchstäbliche Wert im Stack übergeben wird.

0 Stimmen

So süß, und die beste Antwort

0 Stimmen

Genau genommen beginnt der Krieg, wenn Sie sagen wollen, "ein Objekt wird per Referenz übergeben"

235voto

Hank Gay Punkte 67607

Grundsätzlich wirkt sich die Neuzuweisung von Objektparametern nicht auf das Argument aus, z.B.,

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

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

wird "Hah!" anstelle von null ausgeben. Der Grund dafür ist, dass bar eine Kopie des Werts von baz ist, der nur eine Referenz auf "Hah!" darstellt. Wenn es tatsächlich die Referenz selbst wäre, hätte foo baz auf null umdefiniert.

219voto

Eclipse Punkte 43775

Nur um den Unterschied zu zeigen, vergleichen Sie die folgenden C++ und Java Codeausschnitte:

In C++: Hinweis: Schlechter Code - Speicherlecks! Aber es verdeutlicht den Punkt.

void cppMethod(int val, int &ref, Dog obj, Dog &objRef, Dog *objPtr, Dog *&objPtrRef)
{
    val = 7; // Modifiziert die Kopie
    ref = 7; // Modifiziert die Originalvariable
    obj.SetName("obj"); // Modifiziert die Kopie des übergebenen Dog-Objekts
    objRef.SetName("objRef"); // Modifiziert das übergebene Original-Dog-Objekt
    objPtr->SetName("objPtr"); // Modifiziert das Original-Dog-Objekt, auf das der Kopie des Zeigers zeigt.
    objPtr = new Dog("newObjPtr");  // Modifiziert die Kopie des Zeigers und lässt das Originalobjekt unverändert.
    objPtrRef->SetName("objRefPtr"); // Modifiziert das Original-Dog-Objekt, auf das der Originalzeiger zeigt.
    objPtrRef = new Dog("newObjPtrRef"); // Modifiziert den übergebenen Originalzeiger
}

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 ist immer noch 0
    // b ist jetzt auf 7 gesetzt
    // d0 hat immer noch den Namen "d0"
    // d1 hat jetzt den Namen "objRef"
    // d2 hat jetzt den Namen "objPtr"
    // d3 hat jetzt den Namen "newObjPtrRef"
}

In Java,

public static void javaMethod(int val, Dog objPtr)
{
   val = 7; // Modifiziert die Kopie
   objPtr.SetName("objPtr") // Modifiziert das Original-Dog-Objekt, auf das die Kopie des Zeigers zeigt.
   objPtr = new Dog("newObjPtr");  // Modifiziert die Kopie des Zeigers und lässt das Originalobjekt unverändert.
}

public static void main()
{
    int a = 0;
    Dog d0 = new Dog("d0");
    javaMethod(a, d0);
    // a ist immer noch 0
    // d0 hat jetzt den Namen "objPtr"
}

Java hat nur zwei Arten der Übergabe: nach Wert für eingebaute Datentypen und nach Wert des Zeigers für Objekttypen.

1 Stimmen

Dies zeigt, dass Java nicht nach Wert übergeben wird, da es nicht das gesamte Objekt auf den Stapel kopiert wie C++ es tut, wie im obigen Beispiel gezeigt - ..., Hund-Objekt,...

3 Stimmen

Nein, Java übergibt Referenzen per Wert. Deshalb ändert sich das ursprüngliche Dog-Objekt nicht, wenn Sie objPtr im Java-Beispiel überschreiben. Wenn Sie jedoch das Objekt ändern, auf das objPtr zeigt, geschieht dies.

212voto

John Channing Punkte 6373

Java übergibt Referenzen auf Objekte per Wert.

6 Stimmen

Keine nützliche Erklärung.

0 Stimmen

Was du meinst, ist, dass Java den Wert zur Referenz kopiert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X