Ich dachte immer, Java sei eine Referenz .
Ich habe jedoch einige Blog-Beiträge gesehen (zum Beispiel diesen Blog ), die behaupten, dass dies nicht der Fall ist.
Ich glaube nicht, dass ich den Unterschied verstehe, den sie machen.
Was ist die Erklärung?
java
methods
parameter-passing
pass-by-reference
pass-by-value
Benutzer4315
quelle
quelle
call-by-value
undcall-by-reference
in sehr entscheidender Weise unterscheidet . (Ich persönlich bevorzuge die Verwendungcall-by-object-sharing
über diese Tagecall-by-value[-of-the-reference]
, da dies die Semantik auf hohe Ebene beschreibt und schafft keinen Konflikt mitcall-by-value
, das ist die zugrunde liegende Implementierung.)swap(x,y)
Test bestanden wird .Antworten:
Java ist immer ein Pass-by-Value . Wenn wir den Wert eines Objekts übergeben, übergeben wir leider den Verweis darauf. Dies ist für Anfänger verwirrend.
Es geht so:
Im obigen Beispiel
aDog.getName()
wird immer noch zurückgegeben"Max"
. Der WertaDog
innerhalbmain
wird in der Funktionfoo
mit nicht geändert,Dog
"Fifi"
da die Objektreferenz als Wert übergeben wird. Wenn es als Referenz übergeben wurde, dann wird dieaDog.getName()
inmain
zurückkommen würde"Fifi"
nach dem Aufruffoo
.Gleichfalls:
Im obigen Beispiel
Fifi
ist der Name des Hundes nach dem Aufruf von angegeben,foo(aDog)
da der Name des Objekts innerhalb von festgelegt wurdefoo(...)
. Alle Operationen,foo
die ausgeführt werden,d
sind so, dass sie für alle praktischen Zwecke ausgeführt werdenaDog
, es ist jedoch nicht möglich, den Wert der VariablenaDog
selbst zu ändern .quelle
Ich habe gerade bemerkt, dass Sie auf meinen Artikel verwiesen haben .
Die Java-Spezifikation besagt, dass alles in Java als Wert übergeben wird. In Java gibt es kein "Pass-by-Reference".
Der Schlüssel zum Verständnis ist, dass so etwas
ist kein Hund; Es ist eigentlich ein Hinweis auf einen Hund.
Was das bedeutet, ist, wenn Sie haben
Sie übergeben im Wesentlichen die Adresse des erstellten
Dog
Objekts an diefoo
Methode.(Ich sage im Wesentlichen, weil Java-Zeiger keine direkten Adressen sind, aber es ist am einfachsten, sie so zu sehen.)
Angenommen, das
Dog
Objekt befindet sich an der Speicheradresse 42. Dies bedeutet, dass wir 42 an die Methode übergeben.wenn die Methode definiert wäre als
Schauen wir uns an, was passiert.
someDog
wird auf den Wert 42 gesetztsomeDog
wird gefolgt, auf dasDog
es zeigt (dasDog
Objekt an Adresse 42)Dog
(der an Adresse 42) gebeten wird, seinen Namen in Max zu ändernDog
wird erstellt. Nehmen wir an, er ist an der Adresse 74someDog
74 zuDog
Punkt gefolgt, auf den es zeigt (dasDog
Objekt an Adresse 74).Dog
(der an Adresse 74) wird gebeten, seinen Namen in Rowlf zu ändernLassen Sie uns nun darüber nachdenken, was außerhalb der Methode passiert:
Hat sich
myDog
geändert?Da ist der Schlüssel.
Wenn man bedenkt, dass dies
myDog
ein Zeiger und kein tatsächlicher istDog
, lautet die Antwort NEIN.myDog
hat noch den Wert 42; Es zeigt immer noch auf das OriginalDog
(aber beachten Sie, dass der Name aufgrund der Zeile "AAA" jetzt "Max" lautet - immer noch derselbe Hund;myDog
der Wert hat sich nicht geändert.)Es ist absolut gültig, einer Adresse zu folgen und zu ändern, was am Ende steht. das ändert die Variable jedoch nicht.
Java funktioniert genau wie C. Sie können einen Zeiger zuweisen, den Zeiger an eine Methode übergeben, dem Zeiger in der Methode folgen und die Daten ändern, auf die verwiesen wurde. Sie können jedoch nicht ändern, wohin dieser Zeiger zeigt.
In C ++, Ada, Pascal und anderen Sprachen, die die Referenzübergabe unterstützen, können Sie die übergebene Variable tatsächlich ändern.
Wenn Java eine Referenzpass-Semantik
foo
hätte, hätte sich die oben definierte Methode geändert, wohin siemyDog
zeigte, als siesomeDog
in Zeile BBB zugewiesen wurde .Stellen Sie sich Referenzparameter als Aliase für die übergebene Variable vor. Wenn dieser Alias zugewiesen wird, gilt dies auch für die übergebene Variable.
quelle
Java übergibt Argumente immer als Wert , NICHT als Referenz.
Lassen Sie mich dies anhand eines Beispiels erklären :
Ich werde dies in Schritten erklären:
Deklarieren Sie eine Referenz mit dem Namen
f
typeFoo
und weisen Sie ihr ein neues ObjektFoo
mit einem Attribut zu"f"
.Auf der Methodenseite wird eine Referenz vom Typ
Foo
mit einem Namena
deklariert und zunächst zugewiesennull
.Wenn Sie die Methode aufrufen
changeReference
, wird der Referenza
das Objekt zugewiesen, das als Argument übergeben wird.Deklarieren Sie eine Referenz mit dem Namen
b
typeFoo
und weisen Sie ihr ein neues ObjektFoo
mit einem Attribut zu"b"
.a = b
macht eine neue Zuordnung zu der Referenza
, nichtf
, des Objekts , das dessen Attribut ist"b"
.Beim Aufrufen der
modifyReference(Foo c)
Methode wird eine Referenzc
erstellt und dem Objekt ein Attribut zugewiesen"f"
.c.setAttribute("c");
ändert das Attribut des Objekts, auf das verwiesenc
wird, und es ist dasselbe Objekt, auf das verwiesenf
wird.Ich hoffe, Sie verstehen jetzt, wie das Übergeben von Objekten als Argumente in Java funktioniert :)
quelle
a
auf dasselbe Objekt verweist wief
(und niemals eine eigene Kopie des Objekts darauff
zeigt), sollten alle Änderungen am Objekt, die mit verwendeta
werden, ebenfallsf
geändert werden (da beide mit demselben Objekt arbeiten ), muss also irgendwanna
eine eigene Kopie der Objektpunkte bekommenf
.Dies gibt Ihnen einige Einblicke in die Funktionsweise von Java bis zu dem Punkt, dass Sie in Ihrer nächsten Diskussion über Java, das als Referenz oder als Wert übergeben wird, nur lächeln :-)
Schritt eins: Bitte löschen Sie das Wort, das mit 'p' "_ _ _ _ _ _ _" beginnt, aus Ihrem Kopf, insbesondere wenn Sie aus anderen Programmiersprachen stammen. Java und 'p' können nicht im selben Buch, Forum oder sogar txt geschrieben werden.
Schritt zwei Denken Sie daran, dass Sie beim Übergeben eines Objekts an eine Methode die Objektreferenz und nicht das Objekt selbst übergeben.
Stellen Sie sich nun vor, was die Referenz / Variable eines Objekts tut / ist:
Im Folgenden (bitte versuchen Sie nicht, dies zu kompilieren / auszuführen ...):
Was geschieht?
Ein Bild sagt mehr als tausend Worte:
Beachten Sie, dass die Pfeile anotherReferenceToTheSamePersonObject auf das Objekt und nicht auf die variable Person gerichtet sind!
Wenn Sie es nicht verstanden haben, vertrauen Sie mir einfach und denken Sie daran, dass es besser ist zu sagen, dass Java als Wert übergeben wird . Nun, übergeben Sie den Referenzwert . Na ja, noch besser ist das Übergeben einer Kopie des Variablenwerts! ;)
Sie können mich jetzt gerne hassen, aber beachten Sie, dass es angesichts dessen keinen Unterschied zwischen der Übergabe primitiver Datentypen und Objekten gibt, wenn es um Methodenargumente geht.
Sie übergeben immer eine Kopie der Bits des Referenzwerts!
Natürlich können Sie es kurz machen und einfach sagen, dass Java ein Pass-by-Value ist!
quelle
public void foo(Car car){ ... }
,car
lokal zufoo
und es enthält den Heap-Speicherort des Objekts? Wenn ich alsocar
den Wert um änderecar = new Car()
, zeigt er auf ein anderes Objekt auf dem Heap? und wenn ichcar
den Eigenschaftswert um änderecar.Color = "Red"
, wird das Objekt im Heap, auf das gezeigtcar
wird, geändert. Auch ist es das gleiche in C #? Bitte antworte! Vielen Dank!System.out.println(person.getName());
was wird angezeigt? "Tom" oder "Jerry"? Dies ist das Letzte, was mir helfen wird, diese Verwirrung zu überwinden.Java wird immer von Wert übergeben, ohne Ausnahmen, immer .
Wie kommt es also, dass jeder davon verwirrt sein kann und glaubt, dass Java als Referenz übergeben wird, oder dass er ein Beispiel für Java hat, das als Referenzübergabe fungiert? Der entscheidende Punkt ist , dass Java nie den direkten Zugriff auf die Werte liefert Objekte selbst , in allen Umständen. Der einzige Zugriff auf Objekte erfolgt über einen Verweis auf dieses Objekt. Da auf Java-Objekte immer über eine Referenz und nicht direkt zugegriffen wird, werden Felder und Variablen sowie Methodenargumente häufig als Objekte bezeichnet , wenn sie pedantisch nur Verweise auf Objekte sind .Die Verwirrung ergibt sich aus dieser (genau genommen falschen) Änderung der Nomenklatur.
Also, wenn Sie eine Methode aufrufen
int
,long
, etc.), ist der Durchgang durch den Wert der Ist - Wert des Primitiv (beispielsweise 3).Wenn Sie also
doSomething(foo)
undpublic void doSomething(Foo foo) { .. }
die beiden Foos Referenzen kopiert haben , die auf dieselben Objekte verweisen.Das Übergeben eines Verweises auf ein Objekt als Wert ähnelt natürlich dem Übergeben eines Objekts als Verweis (und ist in der Praxis nicht davon zu unterscheiden).
quelle
Java übergibt Referenzen nach Wert.
Sie können also die Referenz, die übergeben wird, nicht ändern.
quelle
Ich habe das Gefühl, dass es nicht besonders hilfreich ist, über "Pass-by-Reference vs Pass-by-Value" zu streiten.
Wenn Sie sagen, "Java ist ein Pass-by-Whatever (Referenz / Wert)", erhalten Sie in beiden Fällen keine vollständige Antwort. Hier sind einige zusätzliche Informationen, die hoffentlich helfen werden, zu verstehen, was im Speicher passiert.
Crashkurs auf Stack / Heap, bevor wir zur Java-Implementierung kommen: Die Werte werden auf eine schöne, geordnete Weise auf und ab des Stacks verschoben, wie ein Stapel Teller in einer Cafeteria. Der Speicher im Heap (auch als dynamischer Speicher bezeichnet) ist zufällig und unorganisiert. Die JVM findet nur Speicherplatz, wo immer sie kann, und gibt ihn frei, da die Variablen, die ihn verwenden, nicht mehr benötigt werden.
Okay. Zunächst werden lokale Grundelemente auf den Stapel gelegt. Also dieser Code:
führt dazu:
Wenn Sie ein Objekt deklarieren und instanziieren. Das eigentliche Objekt geht auf den Haufen. Was geht auf den Stapel? 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. Sie müssen nur wissen, dass die Adresse des Objekts auf dem Stapel liegt.
Wie so:
Ein Array ist ein Objekt, also geht es auch auf den Heap. Und was ist mit den Objekten im Array? Sie erhalten ihren eigenen Heap-Speicherplatz, und die Adresse jedes Objekts befindet sich im Array.
Was wird also übergeben, wenn Sie eine Methode aufrufen? Wenn Sie ein Objekt übergeben, übergeben Sie tatsächlich die Adresse des Objekts. Einige sagen vielleicht den "Wert" der Adresse, andere sagen, es ist nur ein Verweis auf das Objekt. Dies ist die Entstehung des heiligen Krieges zwischen "Referenz" - und "Wert" -Vertretern. Was Sie es nennen, ist nicht so wichtig, als dass Sie verstehen, dass die Adresse des Objekts übergeben wird.
Ein String wird erstellt und Speicherplatz dafür wird im Heap zugewiesen, und die Adresse des Strings wird auf dem Stapel gespeichert und mit dem Bezeichner versehen
hisName
, da die Adresse des zweiten Strings mit der des ersten übereinstimmt, kein neuer String erstellt wird und Es wird kein neuer Heap-Speicherplatz zugewiesen, aber ein neuer Bezeichner wird auf dem Stapel erstellt. Dann rufen wir aufshout()
: Ein neuer Stapelrahmen wird erstellt und ein neuer Bezeichnername
wird erstellt und die Adresse des bereits vorhandenen Strings zugewiesen.Also, Wert, Referenz? Sie sagen "Kartoffel".
quelle
Vergleichen Sie die folgenden C ++ - und Java- Snippets , um den Kontrast zu zeigen :
In C ++: Hinweis: Schlechter Code - Speicherlecks! Aber es zeigt den Punkt.
In Java
In Java gibt es nur zwei Arten der Übergabe: nach Wert für integrierte Typen und nach Wert des Zeigers für Objekttypen.
quelle
Dog **objPtrPtr
dem C ++ - Beispiel hinzufügen , auf diese Weise können wir ändern, auf was der Zeiger "zeigt".Java übergibt Verweise auf Objekte nach Wert.
quelle
Grundsätzlich wirkt sich die Neuzuweisung von Objektparametern nicht auf das Argument aus, z.
auszudrucken wird
"Hah!"
stattnull
. Der Grund dafür ist, dassbar
es sich um eine Kopie des Werts von handeltbaz
, auf die nur verwiesen wird"Hah!"
. Wenn es die tatsächliche Referenz selbst wäre, dannfoo
hätte neu definiertbaz
zunull
.quelle
Ich kann nicht glauben, dass noch niemand Barbara Liskov erwähnt hat. Als sie 1974 die CLU entwarf, stieß sie auf dasselbe Terminologieproblem und erfand den Begriff Call by Sharing (auch als Call by Object-Sharing und Call by Object bezeichnet ) für diesen speziellen Fall von "Call by Value", bei dem sich der Wert befindet eine Referenz".
quelle
Der Kern der Sache ist, dass die Wortreferenz im Ausdruck "Referenzübergabe" etwas völlig anderes bedeutet als die übliche Bedeutung der Wortreferenz in Java.
Normalerweise bedeutet in Java Referenz eine Referenz auf ein Objekt . Die technischen Begriffe, die als Referenz / Wert aus der Programmiersprachtheorie verwendet werden, sprechen jedoch von einer Referenz auf die Speicherzelle, in der sich die Variable befindet , was etwas völlig anderes ist.
quelle
In Java ist alles eine Referenz. Wenn Sie
Point pnt1 = new Point(0,0);
also Folgendes haben: Java führt Folgendes aus:Java übergibt keine Methodenargumente als Referenz. es übergibt sie nach Wert. Ich werde ein Beispiel von dieser Seite verwenden :
Ablauf des Programms:
Erstellen von zwei verschiedenen Punktobjekten mit zwei verschiedenen zugeordneten Referenzen.
Wie erwartet wird die Ausgabe sein:
In dieser Zeile geht 'Pass-by-Value' ins Spiel ...
Referenzen
pnt1
undpnt2
werden von Wert übergeben , um die schwierige Methode, was bedeutet , dass nun bei Ihnen Referenzenpnt1
undpnt2
haben ihrecopies
Namenarg1
undarg2
.Sopnt1
undarg1
Punkte auf das gleiche Objekt. (Gleiches gilt fürpnt2
undarg2
)In der
tricky
Methode:Weiter in der
tricky
MethodeHier legen Sie zunächst neue erstellen
temp
Punktreferenz , die wird Punkt auf derselben Stelle wiearg1
Referenz. Dann verschieben Sie die Referenzarg1
, um auf dieselbe Stelle wie diearg2
Referenz zu zeigen. Schließlicharg2
wird darauf wie an der gleichen Stelletemp
.Von hier Umfang
tricky
Verfahren gegangen ist , und Sie haben keinen Zugang mehr zu den Referenzen:arg1
,arg2
,temp
. Wichtig ist jedoch, dass alles, was Sie mit diesen Referenzen tun, wenn sie sich im Leben befinden, das Objekt, auf das sie verweisen , dauerhaft beeinflusst .tricky
Wenn Sie also nach dem Ausführen der Methode zu zurückkehrenmain
, haben Sie folgende Situation:Die vollständige Ausführung des Programms erfolgt nun wie folgt:
quelle
arg1.x = 1; arg1.y = 1; arg2.x = 2; arg2.y = 2;
, so dass arg1 jetzt die pnt2-Aktualisierung und arg2 jetzt die pnt1-Referenz enthält, also der DruckX1: 2 Y1: 2 X2: 1 Y2: 1
Java wird immer als Wert übergeben, nicht als Referenz
Zunächst müssen wir verstehen, was Wertübergabe und Referenzübergabe sind.
Wert übergeben bedeutet, dass Sie eine Kopie des übergebenen Werts des Aktualparameters im Speicher erstellen. Dies ist eine Kopie des Inhalts des Aktualparameters .
Referenzübergabe (auch als Adressübergabe bezeichnet) bedeutet, dass eine Kopie der Adresse des Aktualparameters gespeichert wird .
Manchmal kann Java die Illusion vermitteln, als Referenz zu gelten. Lassen Sie uns anhand des folgenden Beispiels sehen, wie es funktioniert:
Die Ausgabe dieses Programms ist:
Lassen Sie uns Schritt für Schritt verstehen:
Wie wir alle wissen, wird ein Objekt im Heap erstellt und der Referenzwert an t zurückgegeben. Angenommen, der Wert von t ist
0x100234
(wir kennen den tatsächlichen internen Wert der JVM nicht, dies ist nur ein Beispiel).Wenn die Referenz t an die Funktion übergeben wird, wird der tatsächliche Referenzwert des Objekttests nicht direkt übergeben, sondern eine Kopie von t erstellt und anschließend an die Funktion übergeben. Da es als Wert übergeben wird , wird eine Kopie der Variablen und nicht die tatsächliche Referenz übergeben. Da wir sagten, der Wert von t sei
0x100234
, haben sowohl t als auch f den gleichen Wert und daher zeigen sie auf das gleiche Objekt.Wenn Sie etwas in der Funktion unter Verwendung von Referenz f ändern, wird der vorhandene Inhalt des Objekts geändert. Deshalb haben wir die Ausgabe erhalten
changevalue
, die in der Funktion aktualisiert wird.Um dies besser zu verstehen, betrachten Sie das folgende Beispiel:
Wird das ein werfen
NullPointerException
? Nein, da nur eine Kopie der Referenz übergeben wird. Im Falle einer Referenzübergabe hätte es einNullPointerException
, wie unten gezeigt, werfen können :Hoffentlich hilft das.
quelle
Eine Referenz ist immer ein Wert, wenn sie dargestellt wird, unabhängig davon, welche Sprache Sie verwenden.
Schauen wir uns Assembly oder eine Speicherverwaltung auf niedriger Ebene an. Auf CPU-Ebene wird ein Verweis auf etwas sofort zu einem Wert, wenn er in den Speicher oder in eines der CPU-Register geschrieben wird. (Deshalb ist Zeiger eine gute Definition. Es ist ein Wert, der gleichzeitig einen Zweck hat.)
Daten im Speicher haben einen Ort und an dieser Stelle gibt es einen Wert (Byte, Wort, was auch immer). In Montage haben wir eine praktische Lösung , die eine geben , Namen zu bestimmtem Ort (auch bekannt als Variable), aber wenn Sie den Code kompiliert, ersetzt der Assembler einfach Namen mit der festgelegten Stelle genau wie Ihr Browser ersetzt Domain - Namen mit IP - Adressen.
Bis ins Mark ist es technisch unmöglich, einen Verweis auf irgendetwas in irgendeiner Sprache zu übergeben, ohne es darzustellen (wenn es sofort zu einem Wert wird).
Nehmen wir an, wir haben eine Variable Foo, ihre Position befindet sich im 47. Byte im Speicher und ihr Wert ist 5. Wir haben eine weitere Variable Ref2Foo, die sich im 223. Byte im Speicher befindet, und ihr Wert wird 47. Dieser Ref2Foo könnte eine technische Variable sein , nicht explizit vom Programm erstellt. Wenn Sie nur 5 und 47 ohne weitere Informationen betrachten, sehen Sie nur zwei Werte . Wenn Sie sie als Referenz verwenden, müssen
5
wir reisen , um zu erreichen :So funktionieren Sprungtabellen.
Wenn wir eine Methode / Funktion / Prozedur mit dem Wert von Foo aufrufen möchten, gibt es abhängig von der Sprache und den verschiedenen Methodenaufrufmodi einige Möglichkeiten, die Variable an die Methode zu übergeben :
In allen Fällen, in denen ein Wert - eine Kopie eines vorhandenen Werts - erstellt wurde, liegt es nun an der Empfangsmethode, diesen zu verarbeiten. Wenn Sie "Foo" in die Methode schreiben, wird diese entweder aus EAX ausgelesen oder automatisch dereferenziert oder doppelt dereferenziert. Der Vorgang hängt davon ab, wie die Sprache funktioniert und / oder was der Foo-Typ vorschreibt. Dies ist dem Entwickler verborgen, bis er den Dereferenzierungsprozess umgeht. Eine Referenz ist also ein Wert, wenn sie dargestellt wird, da eine Referenz ein Wert ist, der verarbeitet werden muss (auf Sprachebene).
Jetzt haben wir Foo an die Methode übergeben:
Foo = 9
wirkt sich das Ändern von Foo ( ) nur auf den lokalen Bereich aus, da Sie über eine Kopie des Werts verfügen. Innerhalb der Methode können wir nicht einmal feststellen, wo sich der ursprüngliche Foo im Speicher befand.Foo = 11
) ändern , kann dies Foo global ändern (abhängig von der Sprache, dh Java oder wie Pascalsprocedure findMin(x, y, z: integer;
var m: integer);
). Wenn jedoch die Sprache können Sie den dereferenzieren Prozess umgehen, die Sie ändern können47
, sagen49
. Zu diesem Zeitpunkt scheint Foo geändert worden zu sein, wenn Sie es gelesen haben, da Sie den lokalen Zeiger darauf geändert haben . Und wenn Sie dieses Foo innerhalb der Methode (Foo = 12
) ändern, werden Sie wahrscheinlich die Ausführung des Programms FUBAR (auch bekannt als Segfault), da Sie in einen anderen Speicher als erwartet schreiben. Sie können sogar einen Bereich ändern, der ausführbare Dateien enthalten soll Programm und Schreiben darauf ändern den laufenden Code (Foo ist jetzt nicht bei47
). ABER Foo's Wert von47
hat sich nicht global geändert, nur die innerhalb der Methode, da47
es sich auch um eine Kopie der Methode handelte.223
innerhalb der Methode Änderungen vornehmen, entsteht das gleiche Chaos wie in 3. oder 4. (ein Zeiger, der auf einen jetzt schlechten Wert zeigt, der wiederum als Zeiger verwendet wird), aber dies ist immer noch ein lokaler Problem, da 223 kopiert wurde . Wenn Sie jedoch in der Lage sind, den angegebenen Wert zu dereferenzierenRef2Foo
( dh223
), zu erreichen und zu ändern47
, z. B. zu49
, wirkt sich dies global auf Foo aus , da in diesem Fall die Methoden eine Kopie erhalten haben223
, die referenzierte Methode jedoch47
nur einmal vorhanden ist, und diese ändern to49
führt jedeRef2Foo
doppelte Dereferenzierung zu einem falschen Wert.Wenn Sie nur unwichtige Details auswählen, geben selbst Sprachen, die als Referenz übergeben werden, Werte an Funktionen weiter. Diese Funktionen wissen jedoch, dass sie diese für Dereferenzierungszwecke verwenden müssen. Diese Übergabe der Referenz als Wert ist dem Programmierer nur verborgen, da sie praktisch unbrauchbar ist und die Terminologie nur als Referenz übergeben wird .
Eine strikte Übergabe nach Wert ist ebenfalls nutzlos. Dies würde bedeuten, dass jedes Mal, wenn wir eine Methode mit dem Array als Argument aufrufen, ein 100-MByte-Array kopiert werden muss. Daher kann Java nicht strikt nach Wert übergeben werden. Jede Sprache würde einen Verweis auf dieses riesige Array (als Wert) übergeben und entweder einen Copy-on-Write-Mechanismus verwenden, wenn dieses Array lokal innerhalb der Methode geändert werden kann, oder es der Methode (wie Java) ermöglicht, das Array global (von) zu ändern Die Ansicht des Anrufers) und einige Sprachen ermöglichen es, den Wert der Referenz selbst zu ändern.
Kurz gesagt und in Javas eigener Terminologie ist Java ein Pass-by-Wert, bei dem Wert sein kann: entweder ein realer Wert oder ein Wert , der eine Referenz darstellt .
quelle
addr
tut nicht typisierten es,@
tut es mit Art, und Sie können die referenzierte Variable später ändern (lokal kopiert diejenigen ausgenommen) bekannt . Aber ich verstehe nicht, warum Sie das tun würden. Dieser Zettel in Ihrem Beispiel (Objekt Nr. 24601) ist eine Referenz. Er dient dazu, das Array im Speicher zu finden. Er enthält keine Array-Daten an sich. Wenn Sie Ihr Programm neu starten, erhält dasselbe Array möglicherweise eine andere Objekt-ID, auch wenn der Inhalt derselbe ist wie im vorherigen Lauf.AtomicReference
und weder die Referenz noch sein Ziel verfügbar macht, sondern Methoden enthält, um Dinge mit dem Ziel zu tun; Sobald der Code, an den das Objekt übergeben wurde, zurückgegeben wird, sollte derAtomicReference
[auf den sein Ersteller einen direkten Verweis geführt hat] ungültig gemacht und aufgegeben werden. Das würde die richtige Semantik liefern, aber es wäre langsam und schwierig.Java ist ein Aufruf nach Wert
Wie es funktioniert
Sie übergeben immer eine Kopie der Bits des Referenzwerts!
Wenn es sich um einen primitiven Datentyp handelt, enthalten diese Bits den Wert des primitiven Datentyps selbst. Wenn wir also den Wert des Headers innerhalb der Methode ändern, werden die Änderungen außerhalb nicht berücksichtigt.
Wenn es sich um einen Objektdatentyp wie Foo foo = new Foo () handelt, wird in diesem Fall eine Kopie der Adresse des Objekts wie eine Dateiverknüpfung übergeben. Nehmen wir an, wir haben eine Textdatei abc.txt unter C: \ desktop und nehmen eine Verknüpfung von an die gleiche Datei und legen Sie diese in C: \ desktop \ abc-Verknüpfung. Wenn Sie also über C: \ desktop \ abc.txt auf die Datei zugreifen und ' Stapelüberlauf ' schreiben und die Datei schließen, öffnen Sie die Datei erneut über die Verknüpfung write "ist die größte Online-Community, die Programmierer lernen können", dann lautet die vollständige Dateiänderung "Stack Overflow ist die größte Online-Community, die Programmierer lernen können".Das heißt, es spielt keine Rolle, von wo aus Sie die Datei öffnen. Jedes Mal, wenn wir auf dieselbe Datei zugreifen, können wir hier Foo als Datei annehmen und annehmen, dass foo bei 123hd7h gespeichert ist (ursprüngliche Adresse wie C: \ desktop \ abc.txt ). Adresse und 234jdid (kopierte Adresse wie C: \ desktop \ abc-Verknüpfung, die tatsächlich die ursprüngliche Adresse der darin enthaltenen Datei enthält). Machen Sie zum besseren Verständnis eine Verknüpfungsdatei und fühlen Sie sich.
quelle
Es gibt bereits gute Antworten, die dies abdecken. Ich wollte einen kleinen Beitrag leisten, indem ich ein sehr einfaches Beispiel (das kompiliert wird) mit den Verhaltensweisen zwischen Pass-by-Reference in c ++ und Pass-by-Value in Java teile.
Ein paar Punkte:
C ++ Pass als Referenzbeispiel:
Java übergeben "eine Java-Referenz" als Wertbeispiel
BEARBEITEN
Einige Leute haben Kommentare geschrieben, die darauf hinweisen, dass sie entweder meine Beispiele nicht betrachten oder das C ++ - Beispiel nicht erhalten. Ich bin mir nicht sicher, wo sich die Trennung befindet, aber das Erraten des c ++ - Beispiels ist nicht klar. Ich poste das gleiche Beispiel in Pascal, weil ich denke, dass Pass-by-Reference in Pascal sauberer aussieht, aber ich könnte mich irren. Ich könnte die Leute mehr verwirren; Ich hoffe nicht.
In Pascal werden als Referenz übergebene Parameter als "var-Parameter" bezeichnet. Beachten Sie in der folgenden Prozedur setToNil das Schlüsselwort 'var' vor dem Parameter 'ptr'. Wenn ein Zeiger an diese Prozedur übergeben wird, wird er als Referenz übergeben . Beachten Sie das Verhalten: Wenn diese Prozedur ptr auf nil setzt (das ist pascal speak for NULL), wird das Argument auf nil gesetzt - das können Sie in Java nicht tun.
BEARBEITEN 2
Einige Auszüge aus "THE Java Programming Language" von Ken Arnold, James Gosling (dem Erfinder von Java) und David Holmes, Kapitel 2, Abschnitt 2.6.5
Er fährt fort, den gleichen Punkt in Bezug auf Objekte zu machen. . .
Und gegen Ende desselben Abschnitts macht er eine breitere Aussage darüber, dass Java nur als Wert und niemals als Referenz gilt.
Dieser Abschnitt des Buches enthält eine ausführliche Erläuterung der Parameterübergabe in Java sowie der Unterscheidung zwischen Referenzübergabe und Wertübergabe und wird vom Ersteller von Java erstellt. Ich würde jeden ermutigen, es zu lesen, besonders wenn Sie immer noch nicht überzeugt sind.
Ich denke, der Unterschied zwischen den beiden Modellen ist sehr subtil. Wenn Sie nicht dort programmiert haben, wo Sie tatsächlich Pass-by-Reference verwendet haben, ist es leicht zu übersehen, wo sich zwei Modelle unterscheiden.
Ich hoffe, dass dies die Debatte regelt, aber wahrscheinlich nicht.
BEARBEITEN 3
Ich könnte ein wenig besessen von diesem Beitrag sein. Wahrscheinlich, weil ich das Gefühl habe, dass die Hersteller von Java versehentlich Fehlinformationen verbreitet haben. Wenn sie anstelle des Wortes "Referenz" für Zeiger etwas anderes verwendet hätten, beispielsweise Dingleberry, hätte es kein Problem gegeben. Man könnte sagen, "Java übergibt Dingleberries nach Wert und nicht nach Referenz", und niemand wäre verwirrt.
Dies ist der Grund, warum nur Java-Entwickler Probleme damit haben. Sie schauen sich das Wort "Referenz" an und glauben genau zu wissen, was das bedeutet, also machen sie sich nicht einmal die Mühe, das gegnerische Argument zu berücksichtigen.
Wie auch immer, ich habe in einem älteren Beitrag einen Kommentar bemerkt, der eine Ballon-Analogie ergab, die mir sehr gut gefallen hat. So sehr, dass ich mich entschied, einige Cliparts zusammenzukleben, um eine Reihe von Cartoons zu erstellen, um den Punkt zu veranschaulichen.
Übergeben einer Referenz als Wert - Änderungen an der Referenz werden nicht im Bereich des Aufrufers angezeigt, die Änderungen am Objekt jedoch. Dies liegt daran, dass die Referenz kopiert wird, aber sowohl das Original als auch die Kopie auf dasselbe Objekt verweisen.
Referenzübergabe - Es gibt keine Kopie der Referenz. Eine einzelne Referenz wird sowohl vom Aufrufer als auch von der aufgerufenen Funktion gemeinsam genutzt. Alle Änderungen an der Referenz oder den Daten des Objekts werden im Bereich des Anrufers berücksichtigt.
BEARBEITEN 4
Ich habe Beiträge zu diesem Thema gesehen, die die Implementierung der Parameterübergabe auf niedriger Ebene in Java beschreiben. Ich finde das großartig und sehr hilfreich, weil es eine abstrakte Idee konkretisiert. Für mich geht es jedoch eher um das in der Sprachspezifikation beschriebene Verhalten als um die technische Umsetzung des Verhaltens. Dies ist ein Auszug aus der Java-Sprachspezifikation, Abschnitt 8.4.1 :
Das heißt, Java erstellt eine Kopie der übergebenen Parameter, bevor eine Methode ausgeführt wird. Wie die meisten Leute, die im College Compiler studiert haben, habe ich "The Dragon Book" verwendet, das DAS Compiler-Buch ist. Es enthält eine gute Beschreibung von "Call-by-Value" und "Call-by-Reference" in Kapitel 1. Die Call-by-Value-Beschreibung stimmt genau mit den Java-Spezifikationen überein.
Als ich in den 90er Jahren Compiler studierte, verwendete ich die erste Ausgabe des Buches von 1986, die Java um 9 oder 10 Jahre älter war. Ich bin jedoch gerade auf eine Kopie der 2. Ausgabe von 2007 gestoßen, in der tatsächlich Java erwähnt wird! Abschnitt 1.6.6 mit der Bezeichnung "Parameterübergabemechanismen" beschreibt die Parameterübergabe ziemlich gut. Hier ist ein Auszug unter der Überschrift "Call-by-Value", in dem Java erwähnt wird:
quelle
Soweit ich weiß, kennt Java Call nur nach Wert. Dies bedeutet, dass Sie für primitive Datentypen mit einer Kopie und für Objekte mit einer Kopie des Verweises auf die Objekte arbeiten. Ich denke jedoch, dass es einige Fallstricke gibt; Dies funktioniert beispielsweise nicht:
Dadurch wird Hello World und nicht World Hello ausgefüllt, da Sie in der Swap-Funktion Kopien verwenden, die keinen Einfluss auf die Referenzen im Main haben. Wenn Ihre Objekte jedoch nicht unveränderlich sind, können Sie sie beispielsweise ändern:
Dadurch wird Hello World in der Befehlszeile ausgefüllt. Wenn Sie StringBuffer in String ändern, wird nur Hello erzeugt, da String unveränderlich ist. Zum Beispiel:
Sie könnten jedoch einen Wrapper für String wie diesen erstellen, der es ermöglicht, ihn mit Strings zu verwenden:
edit: Ich glaube, dies ist auch der Grund, StringBuffer zu verwenden, wenn es darum geht, zwei Strings hinzuzufügen, da Sie das ursprüngliche Objekt ändern können, was Sie mit unveränderlichen Objekten wie String nicht können.
quelle
swap(a, b)
, die (1) austauschta
undb
aus der POV des Aufrufers (2) typunabhängig ist, soweit die statische Typisierung dies zulässt (dh die Verwendung mit einem anderen Typ erfordert nichts weiter als das Ändern der deklarierten Typen vona
undb
). und (3) erfordert nicht, dass der Aufrufer einen Zeiger oder Namen explizit übergibt, dann unterstützt die Sprache die Übergabe als Referenz.Nein, es wird nicht als Referenz übergeben.
Java wird gemäß der Java-Sprachspezifikation als Wert übergeben:
quelle
Lassen Sie mich versuchen, mein Verständnis anhand von vier Beispielen zu erklären. Java ist ein Pass-by-Value und kein Pass-by-Reference
/ **
Wert übergeben
In Java werden alle Parameter als Wert übergeben, dh das Zuweisen eines Methodenarguments ist für den Aufrufer nicht sichtbar.
* /
Beispiel 1:
Ergebnis
Beispiel 2:
/ ** * * Wert übergeben * * /
Ergebnis
Beispiel 3:
/ ** Dieser 'Pass By Value' hat das Gefühl 'Pass By Reference'
Einige Leute sagen, dass primitive Typen und 'String' 'Wert übergeben' und Objekte 'Referenz übergeben' sind.
Anhand dieses Beispiels können wir jedoch verstehen, dass es sich nur um einen tatsächlichen Wert handelt, wobei zu berücksichtigen ist, dass wir hier die Referenz als Wert übergeben. dh: Referenz wird als Wert übergeben. Das ist der Grund, warum sie sich ändern können und dies auch nach dem lokalen Geltungsbereich gilt. Wir können die tatsächliche Referenz jedoch nicht außerhalb des ursprünglichen Bereichs ändern. Was dies bedeutet, zeigt das nächste Beispiel für PassByValueObjectCase2.
* /
Ergebnis
Beispiel 4:
/ **
Zusätzlich zu dem, was in Beispiel 3 (PassByValueObjectCase1.java) erwähnt wurde, können wir die tatsächliche Referenz nicht außerhalb des ursprünglichen Bereichs ändern. "
Hinweis: Ich füge den Code für nicht ein
private class Student
. Die Klassendefinition fürStudent
ist dieselbe wie in Beispiel 3.* /
Ergebnis
quelle
In Java können Sie niemals als Referenz übergeben. Eine der offensichtlichen Möglichkeiten besteht darin, dass Sie mehr als einen Wert aus einem Methodenaufruf zurückgeben möchten. Betrachten Sie das folgende Codebit in C ++:
Manchmal möchten Sie dasselbe Muster in Java verwenden, können dies jedoch nicht. Zumindest nicht direkt. Stattdessen könnten Sie so etwas tun:
Wie in früheren Antworten erläutert, übergeben Sie in Java einen Zeiger auf das Array als Wert in
getValues
. Dies ist ausreichend, da die Methode dann das Array-Element ändert und Sie gemäß Konvention erwarten, dass Element 0 den Rückgabewert enthält. Natürlich können Sie dies auch auf andere Weise tun, z. B. indem Sie Ihren Code so strukturieren, dass dies nicht erforderlich ist, oder eine Klasse erstellen, die den Rückgabewert enthalten oder dessen Festlegung zulassen kann. Das einfache Muster, das Ihnen in C ++ oben zur Verfügung steht, ist in Java jedoch nicht verfügbar.quelle
Ich dachte, ich würde diese Antwort beitragen, um weitere Details aus den Spezifikationen hinzuzufügen.
Erstens, Was ist der Unterschied zwischen durch Bezugnahme vorbei Wert vs. vorbei?
Oder aus Wikipedia zum Thema Pass-by-Reference
Und zum Thema Pass-by-Value
Zweitens müssen wir wissen, was Java in seinen Methodenaufrufen verwendet. In der Java-Sprachspezifikation heißt es
Daher weist es den Wert des Arguments der entsprechenden Parametervariablen zu (oder bindet ihn).
Was ist der Wert des Arguments?
Betrachten wir Referenztypen, die Java Virtual Machine Specification Staaten
Die Java-Sprachspezifikation gibt auch an
Der Wert eines Arguments (eines Referenztyps) ist ein Zeiger auf ein Objekt. Beachten Sie, dass eine Variable, ein Aufruf einer Methode mit einem Rückgabetyp für Referenztypen und ein Ausdruck zur Instanzerstellung (
new ...
) alle in einen Referenztypwert aufgelöst werden.Damit
Alle binden den Wert einer Referenz auf eine
String
Instanz an den neu erstellten Parameter der Methodeparam
. Genau das beschreibt die Definition von Pass-by-Value. Als solches ist Java ein Pass-by-Value .Die Tatsache, dass Sie der Referenz folgen können, um eine Methode aufzurufen oder auf ein Feld des referenzierten Objekts zuzugreifen, ist für die Konversation völlig irrelevant. Die Definition von Pass-by-Reference war
In Java bedeutet das Ändern der Variablen das Neuzuweisen. Wenn Sie in Java die Variable innerhalb der Methode neu zuweisen, bleibt sie für den Aufrufer unbemerkt. Das Ändern des Objekts, auf das die Variable verweist, ist ein völlig anderes Konzept.
Primitive Werte sind auch in der Java Virtual Machine Specification definiert, hier . Der Wert des Typs ist der entsprechende Integral- oder Gleitkommawert, der entsprechend codiert ist (8, 16, 32, 64 usw. Bits).
quelle
In Java werden nur Referenzen übergeben und als Wert übergeben:
Java-Argumente werden alle als Wert übergeben (die Referenz wird kopiert, wenn sie von der Methode verwendet wird):
Bei primitiven Typen ist das Java-Verhalten einfach: Der Wert wird in eine andere Instanz des primitiven Typs kopiert.
Bei Objekten ist dies dasselbe: Objektvariablen sind Zeiger (Buckets), die nur die Objektadresse enthalten , die mit dem Schlüsselwort "new" erstellt wurde, und werden wie primitive Typen kopiert.
Das Verhalten kann anders aussehen als bei primitiven Typen: Da die kopierte Objektvariable dieselbe Adresse enthält (an dasselbe Objekt). Der Inhalt / die Mitglieder des Objekts können innerhalb einer Methode noch geändert werden und später nach außen zugreifen, wodurch die Illusion entsteht, dass das (enthaltende) Objekt selbst als Referenz übergeben wurde.
"String" -Objekte scheinen ein gutes Gegenbeispiel zur städtischen Legende zu sein, die besagt, dass "Objekte als Referenz übergeben werden":
Tatsächlich können Sie mit einer Methode niemals den Wert eines als Argument übergebenen Strings aktualisieren:
Ein String-Objekt enthält Zeichen eines als final deklarierten Arrays , das nicht geändert werden kann. Nur die Adresse des Objekts kann mit "new" durch eine andere ersetzt werden. Wenn Sie "new" zum Aktualisieren der Variablen verwenden, kann nicht von außen auf das Objekt zugegriffen werden, da die Variable ursprünglich als Wert übergeben und kopiert wurde.
quelle
strParam.setChar ( i, newValue )
. Das heißt, Strings werden wie alles andere als Wert übergeben. Da String ein nicht primitiver Typ ist, ist dieser Wert ein Verweis auf das Objekt, das mit new erstellt wurde, und Sie können dies mithilfe von String.intern () überprüfen. .Der Unterschied oder vielleicht nur die Art und Weise, wie ich mich erinnere, als ich den gleichen Eindruck hatte wie das Originalplakat, ist folgender: Java wird immer als Wert übergeben. Alle Objekte (in Java alles außer Primitiven) in Java sind Referenzen. Diese Referenzen werden als Wert übergeben.
quelle
Wie viele Leute bereits erwähnt haben, ist Java immer ein Pass-by-Value
Hier ist ein weiteres Beispiel, das Ihnen hilft, den Unterschied zu verstehen ( das klassische Swap-Beispiel ):
Drucke:
Dies liegt daran, dass iA und iB neue lokale Referenzvariablen sind, die denselben Wert wie die übergebenen Referenzen haben (sie zeigen auf a bzw. b). Der Versuch, die Referenzen von iA oder iB zu ändern, ändert sich also nur im lokalen Bereich und nicht außerhalb dieser Methode.
quelle
Java hat nur einen Wert übergeben. Ein sehr einfaches Beispiel, um dies zu validieren.
quelle
obj
(null
) wurde an übergebeninit
, kein Verweis aufobj
.Ich denke immer an "Pass by Copy". Es ist eine Kopie des Wertes, sei es primitiv oder als Referenz. Wenn es ein Grundelement ist, ist es eine Kopie der Bits, die der Wert sind, und wenn es ein Objekt ist, ist es eine Kopie der Referenz.
Ausgabe von Java PassByCopy:
Primitive Wrapper-Klassen und Strings sind unveränderlich, sodass ein Beispiel mit diesen Typen nicht wie andere Typen / Objekte funktioniert.
quelle
Im Gegensatz zu einigen anderen Sprachen können Sie in Java nicht zwischen Wertübergabe und Referenzübergabe wählen. Alle Argumente werden als Wert übergeben. Ein Methodenaufruf kann zwei Arten von Werten an eine Methode übergeben: Kopien primitiver Werte (z. B. Werte von int und double) und Kopien von Verweisen auf Objekte.
Wenn eine Methode einen Parameter vom primitiven Typ ändert, haben Änderungen am Parameter keine Auswirkung auf den ursprünglichen Argumentwert in der aufrufenden Methode.
Wenn es um Objekte geht, können Objekte selbst nicht an Methoden übergeben werden. Also übergeben wir die Referenz (Adresse) des Objekts. Mit dieser Referenz können wir das Originalobjekt bearbeiten.
So erstellt und speichert Java Objekte: Wenn wir ein Objekt erstellen, speichern wir die Adresse des Objekts in einer Referenzvariablen. Lassen Sie uns die folgende Aussage analysieren.
"Konto Konto1" ist der Typ und Name der Referenzvariablen, "=" ist der Zuweisungsoperator, "Neu" fragt nach dem erforderlichen Speicherplatz vom System. Der Konstruktor rechts vom Schlüsselwort new, der das Objekt erstellt, wird implizit durch das Schlüsselwort new aufgerufen. Die Adresse des erstellten Objekts (Ergebnis des rechten Werts, bei dem es sich um einen Ausdruck handelt, der als "Ausdruck zur Erstellung von Klasseninstanzen" bezeichnet wird) wird dem linken Wert (bei dem es sich um eine Referenzvariable mit einem Namen und einem angegebenen Typ handelt) mithilfe des Zuweisungsoperators zugewiesen.
Obwohl die Referenz eines Objekts als Wert übergeben wird, kann eine Methode dennoch mit dem referenzierten Objekt interagieren, indem sie ihre öffentlichen Methoden unter Verwendung der Kopie der Objektreferenz aufruft. Da die im Parameter gespeicherte Referenz eine Kopie der Referenz ist, die als Argument übergeben wurde, beziehen sich der Parameter in der aufgerufenen Methode und das Argument in der aufrufenden Methode auf dasselbe Objekt im Speicher.
Das Übergeben von Verweisen auf Arrays anstelle der Array-Objekte selbst ist aus Leistungsgründen sinnvoll. Da alles in Java als Wert übergeben wird, wird bei Übergabe von Array-Objekten eine Kopie jedes Elements übergeben. Bei großen Arrays würde dies Zeit verschwenden und erheblichen Speicherplatz für die Kopien der Elemente verbrauchen.
In der Abbildung unten sehen Sie, dass wir in der Hauptmethode zwei Referenzvariablen haben (diese werden in C / C ++ als Zeiger bezeichnet, und ich denke, dieser Begriff erleichtert das Verständnis dieser Funktion.). Primitive und Referenzvariablen werden im Stapelspeicher gespeichert (linke Seite in den Bildern unten). Array1- und Array2-Referenzvariablen "Punkt" (wie C / C ++ - Programmierer es nennen) oder Referenz auf a- und b-Arrays, die Objekte (Werte, die diese Referenzvariablen enthalten, sind Adressen von Objekten) im Heapspeicher sind (rechte Seite in den Bildern unten) .
Wenn wir den Wert der Referenzvariablen array1 als Argument an die reverseArray-Methode übergeben, wird in der Methode eine Referenzvariable erstellt, und diese Referenzvariable zeigt auf dasselbe Array (a).
Also, wenn wir sagen
Bei der reverseArray-Methode wird das Array a geändert.
Wir haben eine andere Referenzvariable in der reverseArray-Methode (Array2), die auf ein Array zeigt. C. Wenn wir sagen würden
Bei der reverseArray-Methode zeigt die Referenzvariable array1 in der Methode reverseArray nicht mehr auf Array a und zeigt auf Array c (gepunktete Linie im zweiten Bild).
Wenn wir den Wert der Referenzvariablen array2 als Rückgabewert der Methode reverseArray zurückgeben und diesen Wert der Referenzvariablen array1 in der Hauptmethode zuweisen, zeigt Array1 in main auf Array c.
Schreiben wir also alle Dinge, die wir jetzt auf einmal getan haben.
Und jetzt, da die reverseArray-Methode beendet ist, sind ihre Referenzvariablen (Array1 und Array2) verschwunden. Das heißt, wir haben jetzt nur die beiden Referenzvariablen in der Hauptmethode Array1 und Array2, die auf die Arrays c bzw. b zeigen. Keine Referenzvariable zeigt auf ein Objekt (Array) a. Es ist also für die Speicherbereinigung geeignet.
Sie können Array1 auch den Wert von array2 in main zuweisen. Array1 würde auf b zeigen.
quelle
Ich habe einen Thread für diese Art von Fragen für gewidmet erstellt beliebige Programmiersprachen hier .
Java wird ebenfalls erwähnt . Hier ist die kurze Zusammenfassung:
quelle
Um es kurz zu machen, Java- Objekte haben einige sehr eigenartige Eigenschaften.
Im Allgemeinen hat Java primitive Typen (
int
,bool
,char
,double
usw.) , die direkt von Wert übergeben werden. Dann hat Java Objekte (alles, was davon herrührtjava.lang.Object
). Objekte werden eigentlich immer über eine Referenz behandelt (eine Referenz ist ein Zeiger, den Sie nicht berühren können). Das bedeutet, dass Objekte tatsächlich als Referenz übergeben werden, da die Referenzen normalerweise nicht interessant sind. Dies bedeutet jedoch, dass Sie nicht ändern können, auf welches Objekt verwiesen wird, da die Referenz selbst als Wert übergeben wird.Klingt das seltsam und verwirrend? Betrachten wir, wie C-Implementierungen als Referenz und als Wert übergeben werden. In C lautet die Standardkonvention "Wert übergeben".
void foo(int x)
Übergibt ein int als Wert.void foo(int *x)
ist eine Funktion, die keinint a
, sondern einen Zeiger auf ein int will :foo(&a)
. Man würde dies mit dem&
Operator verwenden, um eine variable Adresse zu übergeben.Nehmen Sie dies zu C ++, und wir haben Referenzen. Referenzen sind im Grunde genommen (in diesem Zusammenhang) syntaktischer Zucker, der den Zeigerteil der Gleichung verbirgt:
void foo(int &x)
wird von aufgerufenfoo(a)
, wobei der Compiler selbst weiß, dass es sich um eine Referenz handelt und die Adresse der Nichtreferenz übergebena
werden sollte. In Java sind alle Variablen, die sich auf Objekte beziehen, tatsächlich vom Referenztyp, wodurch für die meisten Zwecke und Zwecke ein Aufruf durch Referenz erzwungen wird, ohne dass die fein abgestimmte Steuerung (und Komplexität) beispielsweise von C ++ bereitgestellt wird.quelle