8 Stimmen

Kann mir jemand erklären, was der Grund für die Übergabe durch "Wert" und nicht durch "Referenz" in Java ist?

Ich bin ein ziemlicher Neuling in Java (ich schreibe seit vielen Jahren andere Sachen), und wenn ich nicht gerade etwas übersehe (und ich freue mich, wenn ich hier falsch liege), ist das Folgende ein fataler Fehler...

String foo = new String();
thisDoesntWork(foo);
System.out.println(foo);//this prints nothing

public static void thisDoesntWork(String foo){
   foo = "howdy";
}

Nun, ich bin mir des (ziemlich schlecht formulierten) Konzepts bewusst, dass in Java alles als "Wert" und nicht als "Referenz" übergeben wird, aber String ist ein Objekt und hat alle Arten von Schnickschnack, so dass man erwarten würde, dass im Gegensatz zu einem int ein Benutzer in der Lage wäre, die Sache zu bearbeiten, die an die Methode übergeben wird (und nicht mit dem Wert feststeckt, der durch das überladene =).

Kann mir jemand erklären, was der Grund für diese Designentscheidung war? Wie gesagt, ich will hier nicht Recht haben, und vielleicht übersehe ich etwas Offensichtliches?

0 Stimmen

Ich bin mir nicht ganz sicher, was Sie damit sagen wollen. Bitte klären Sie es ein wenig?

0 Stimmen

Der vorherige Titel war nicht gut, denn es wäre unmöglich, den Inhalt Ihrer Frage über den Titel zu suchen.

0 Stimmen

Kein Problem, dieser Titel macht mehr Sinn :)

2voto

Julien Chastang Punkte 17256

Das Problem ist, dass Sie einen Java-Referenztyp instanziieren. Dann übergeben Sie diesen Referenztyp an eine statische Methode und ordnen ihn einer lokal skalierten Variablen zu.

Das hat nichts mit Unveränderlichkeit zu tun. Genau das Gleiche wäre bei einem veränderbaren Referenztyp passiert.

1voto

Michael Buen Punkte 37103

Wenn wir eine grobe Analogie zwischen C und Assembler herstellen wollen:

void Main()
{ 
     // stack memory address of message is 0x8001.  memory address of Hello is 0x0001.  
     string message = "Hello"; 
     // assembly equivalent of: message = "Hello";
     // [0x8001] = 0x0001

     // message's stack memory address
     printf("%d", &message); // 0x8001

     printf("%d", message); // memory pointed to of message(0x8001): 0x0001
     PassStringByValue(message); // pass the pointer pointed to of message.  0x0001, not 0x8001
     printf("%d", message); // memory pointed to of message(0x8001): 0x0001.  still the same

     // message's stack memory address doesn't change
     printf("%d", &message); // 0x8001
}

void PassStringByValue(string foo)
{
    printf("%d", &foo); // &foo contains foo's *stack* address (0x4001)

    // foo(0x4001) contains the memory pointed to of message, 0x0001
    printf("%d", foo);  // 0x0001
    // World is in memory address 0x0002
    foo = "World";  // on foo's memory address (0x4001), change the memory it pointed to, 0x0002
    // assembly equivalent of: foo = "World":
    // [0x4001] = 0x0002

    // print the new memory pointed by foo
    printf("%d", foo); // 0x0002

    // Conclusion: Not in any way 0x8001 was involved in this function.  Hence you cannot change the Main's message value.
    // foo = "World"  is same as [0x4001] = 0x0002

}

void Main()
{
     // stack memory address of message is 0x8001.  memory address of Hello is 0x0001.  
     string message = "Hello"; 
     // assembly equivalent of: message = "Hello";
     // [0x8001] = 0x0001

     // message's stack memory address
     printf("%d", &message); // 0x8001

     printf("%d", message); // memory pointed to of message(0x8001): 0x0001
     PassStringByRef(ref message); // pass the stack memory address of message.  0x8001, not 0x0001
     printf("%d", message); // memory pointed to of message(0x8001): 0x0002. was changed

     // message's stack memory address doesn't change
     printf("%d", &message); // 0x8001
}

void PassStringByRef(ref string foo)
{
    printf("%d", &foo); // &foo contains foo's *stack* address (0x4001)

    // foo(0x4001) contains the address of message(0x8001)
    printf("%d", foo);  // 0x8001
    // World is in memory address 0x0002
    foo = "World"; // on message's memory address (0x8001), change the memory it pointed to, 0x0002
    // assembly equivalent of: foo = "World":
    // [0x8001] = 0x0002;

    // print the new memory pointed to of message
    printf("%d", foo); // 0x0002

    // Conclusion: 0x8001 was involved in this function.  Hence you can change the Main's message value.
    // foo = "World"  is same as [0x8001] = 0x0002

}

Ein möglicher Grund, warum in Java alles als Wert übergeben wird, ist, dass die Sprachdesigner die Sprache vereinfachen und alles in OOP-Manier machen wollen.

Sie würden lieber einen Integer-Swapper mit Objekten entwerfen, als dass sie eine erstklassige Unterstützung für die Übergabe von By-Referenzen bereitstellen, dasselbe gilt für Delegate (Gosling fühlt sich unwohl mit Zeigern auf Funktionen, er würde diese Funktionalität lieber in Objekte packen) und Enum.

Sie vereinfachen die Sprache zu sehr (alles ist ein Objekt), was dazu führt, dass die meisten Sprachkonstrukte nicht erstklassig unterstützt werden, z. B. Referenzübergabe, Delegierte, Enum, Eigenschaften.

0voto

Bhushan Bhangale Punkte 10651

Sind Sie sicher, dass er null ausgibt? Ich denke, es wird einfach leer sein, da Sie bei der Initialisierung der Variable foo einen leeren String angegeben haben.

Durch die Zuweisung von foo in der thisDoesntWork-Methode wird der Verweis auf die in der Klasse definierte Variable foo nicht geändert, so dass foo in System.out.println(foo) weiterhin auf das alte leere String-Objekt verweist.

0voto

Yevgeny Simkin Punkte 27016

Dave, Sie müssen mir verzeihen (nun, ich denke, Sie "müssen" nicht, aber es wäre mir lieber, Sie täten es), aber diese Erklärung ist nicht sehr überzeugend. Der Sicherheitsgewinn ist ziemlich minimal, da jeder, der den Wert der Zeichenkette ändern muss, einen Weg finden wird, dies mit einem hässlichen Workaround zu tun. Und die Geschwindigkeit?! Sie selbst behaupten (ganz richtig), dass die ganze Sache mit dem + extrem teuer ist.

Der Rest von euch, bitte versteht, dass ich weiß, wie es funktioniert, ich frage nur, WARUM es so funktioniert... bitte hört auf, den Unterschied zwischen den Methoden zu erklären.

(und ich bin wirklich nicht auf einen Streit aus, ich verstehe nur nicht, warum dies eine rationale Entscheidung war).

0voto

mP. Punkte 17565

@Axelle

Kumpel kennen Sie wirklich den Unterschied zwischen Übergabe durch Wert und durch Referenz?

In Java werden sogar Referenzen als Wert übergeben. Wenn Sie eine Referenz auf ein Objekt übergeben, erhalten Sie eine Kopie des Referenzzeigers in der zweiten Variablen. Deshalb kann die zweite Variable geändert werden, ohne die erste zu beeinflussen.

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