Speziell in Java, aber wahrscheinlich auch in anderen Sprachen: Wann wäre es sinnvoll, zwei Verweise auf dasselbe Objekt zu haben?
Beispiel:
Dog a = new Dog();
Dob b = a;
Gibt es eine Situation, in der dies nützlich wäre? Warum ist dies die bevorzugte Lösung, a
wenn Sie mit dem durch dargestellten Objekt interagieren möchten a
?
object-oriented
object-oriented-design
object
Bassinator
quelle
quelle
a
undb
immer auf dasselbe Bezug genommen wird, hat dasDog
keinen Sinn. Wenn sie manchmal könnten, dann ist es sehr nützlich.Antworten:
Ein Beispiel ist, wenn Sie dasselbe Objekt in zwei separaten Listen haben möchten :
Eine andere Verwendung ist, wenn dasselbe Objekt mehrere Rollen spielt :
quelle
Persona batman = new Persona("Batman"); Persona bruce = new Persona("Bruce Wayne"); Persona currentPersona = batman;
- wo Sie mehrere mögliche Werte (oder eine Liste verfügbarer Werte) und einen Verweis auf den aktuell aktiven / ausgewählten haben.currentPersona
verweist auf das eine oder andere Objekt, aber niemals auf beides. Insbesondere könnte es leicht möglich sein , dasscurrentPersona
wird nie aufbruce
, in welchem Fall es ist sicherlich nicht ein Hinweis auf zwei Objekte. Ich würde sagen, dass in meinem Beispiel beidesbatman
undcurrentPersona
Verweise auf dieselbe Instanz sind, aber innerhalb des Programms eine andere semantische Bedeutung haben.Das ist eigentlich eine überraschend tiefe Frage! Erfahrungen mit modernem C ++ (und Sprachen, die aus modernem C ++ stammen, wie z. B. Rust) legen nahe, dass Sie das sehr oft nicht wollen! Für die meisten Daten möchten Sie eine einzelne oder eindeutige ("besitzende") Referenz. Diese Idee ist auch der Hauptgrund für lineare Systeme .
Selbst dann möchten Sie jedoch in der Regel einige kurzlebige "geliehene" Referenzen, die für den kurzfristigen Zugriff auf den Speicher verwendet werden, die jedoch einen erheblichen Teil der Zeit, in der die Daten vorhanden sind, nicht ausreichen. Am häufigsten, wenn Sie ein Objekt als Argument an eine andere Funktion übergeben (Parameter sind auch Variablen!):
Ein weniger häufiger Fall, wenn Sie abhängig von einer Bedingung eines von zwei Objekten verwenden und im Wesentlichen dasselbe tun, unabhängig davon, für welches Sie sich entscheiden:
Zurück zu häufigeren Verwendungen, aber ohne lokale Variablen, wenden wir uns Feldern zu: Widgets in GUI-Frameworks haben häufig übergeordnete Widgets, sodass auf Ihren großen Frame mit zehn Schaltflächen mindestens zehn Verweise verweisen (plus einige weitere) von seinen Eltern und vielleicht von Event-Listenern und so weiter). Jede Art von Objektgraph und einige Arten von Objektbäumen (solche mit Eltern- / Geschwisterreferenzen) haben mehrere Objekte, die sich auf dasselbe Objekt beziehen. Und praktisch jeder Datensatz ist eine Grafik ;-)
quelle
Temporäre Variablen: Beachten Sie den folgenden Pseudocode.
Die Variablen
max
undcandidate
können auf dasselbe Objekt verweisen, aber die Variablenzuordnung ändert sich nach unterschiedlichen Regeln und zu unterschiedlichen Zeiten.quelle
Als Ergänzung zu den anderen Antworten möchten Sie möglicherweise auch eine andere Datenstruktur durchlaufen, beginnend an derselben Stelle. Wenn Sie zum Beispiel eine hatten
BinaryTree a = new BinaryTree(...); BinaryTree b = a
, könnten Sie den Pfad ganz links mita
und den Pfad ganz rechts mit dem Baumb
mit etwas wie folgendem abfahren :Es ist schon eine Weile her, dass ich Java geschrieben habe, sodass der Code möglicherweise nicht korrekt oder sinnvoll ist. Nimm es mehr als Pseudocode.
quelle
Diese Methode eignet sich hervorragend, wenn Sie über mehrere Objekte verfügen, die alle auf ein anderes Objekt zugreifen, das nicht kontextbezogen verwendet werden kann.
Wenn Sie beispielsweise eine Oberfläche mit Registerkarten haben, haben Sie möglicherweise Tab1, Tab2 und Tab3. Möglicherweise möchten Sie auch eine gemeinsame Variable verwenden können, unabhängig davon, auf welcher Registerkarte sich der Benutzer befindet, um Ihren Code zu vereinfachen und zu vermeiden, dass Sie im Handumdrehen herausfinden müssen, auf welcher Registerkarte sich Ihr Benutzer befindet.
Anschließend können Sie in jeder der nummerierten Registerkarten auf Click die Registerkarte CurrentTab so ändern, dass sie auf diese Registerkarte verweist.
Jetzt können Sie in Ihrem Code "CurrentTab" ungestraft aufrufen, ohne wissen zu müssen, auf welchem Tab Sie sich tatsächlich befinden. Sie können auch die Eigenschaften von CurrentTab aktualisieren und sie werden automatisch auf die referenzierte Registerkarte übertragen.
quelle
Es gibt viele Szenarien , wobei
b
muss ein Hinweis auf eine unbekannte sein „a
“, um nützlich zu sein. Bestimmtes:b
beim Kompilieren achten müssen.Beispielsweise:
Parameter
t
ist ein Verweis auf eine Variable von außerhalb des Gültigkeitsbereichs.Rückgabewerte und andere bedingte Werte
biggerThing
undz
sind jeweils Verweise auf entwedera
oderb
. Wir wissen nicht, welche zum Zeitpunkt der Kompilierung.Lambdas und ihre Rückgabewerte
x
ist ein Parameter (Beispiel 1 oben) undt
ist ein Rückgabewert (Beispiel 2 oben)Sammlungen
index["some name"]
ist zu einem großen Teil ein anspruchsvolleres Aussehenb
. Es ist ein Alias für ein Objekt, das erstellt und in die Sammlung eingefügt wurde.Schleifen
t
ist ein Verweis auf ein Element, das von einem Iterator zurückgegeben wurde (Beispiel 2) (vorheriges Beispiel).quelle
Es ist ein entscheidender Punkt, aber meiner Meinung nach ist es wert, verstanden zu werden.
Alle OO-Sprachen machen immer Kopien von Referenzen und kopieren niemals ein Objekt 'unsichtbar'. Es wäre viel schwieriger, Programme zu schreiben, wenn die OO-Sprachen anders funktionieren würden. Beispielsweise könnten Funktionen und Methoden ein Objekt niemals aktualisieren. Java und die meisten OO-Sprachen wären ohne zusätzliche Komplexität kaum zu verwenden.
Ein Objekt in einem Programm soll eine Bedeutung haben. Zum Beispiel repräsentiert es etwas Bestimmtes in der realen physischen Welt. In der Regel ist es sinnvoll, viele Verweise auf dasselbe zu haben. Beispielsweise kann meine Privatadresse vielen Personen und Organisationen zugewiesen werden, und diese Adresse bezieht sich immer auf denselben physischen Standort. Der erste Punkt ist also, dass Objekte oft etwas Spezifisches, Reales oder Konkretes darstellen. und so ist es äußerst nützlich, in der Lage zu sein, viele Verweise auf dasselbe zu haben. Sonst wäre es schwieriger, Programme zu schreiben.
Jedes Mal, wenn Sie
a
als Argument / Parameter an eine andere Funktion übergeben, z. B.foo(Dog aDoggy);
eine Methode aufrufen oder anwenden
a
, erstellt der zugrunde liegende Programmcode eine Kopie der Referenz, um eine zweite Referenz auf dasselbe Objekt zu erstellen.Wenn sich der Code mit einer kopierten Referenz in einem anderen Thread befindet, können beide gleichzeitig verwendet werden, um auf dasselbe Objekt zuzugreifen.
In den meisten nützlichen Programmen wird es also mehrere Verweise auf dasselbe Objekt geben, da dies die Semantik der meisten OO-Programmiersprachen ist.
Nun, wenn wir darüber nachdenken, da die Referenzübergabe der einzige Mechanismus ist, der in vielen OO-Sprachen verfügbar ist (C ++ unterstützt beide), können wir davon ausgehen, dass dies das 'richtige' Standardverhalten ist .
IMHO ist die Verwendung von Referenzen aus mehreren Gründen die richtige Standardeinstellung :
Es gibt auch ein Effizienzargument; Das Kopieren ganzer Objekte ist weniger effizient als das Kopieren einer Referenz. Ich denke jedoch, dass das den Punkt verfehlt. Mehrfachverweise auf dasselbe Objekt sind sinnvoller und einfacher zu verwenden, da sie der Semantik der realen physischen Welt entsprechen.
Also, meiner Meinung nach, ist es normalerweise sinnvoll, mehrere Verweise auf dasselbe Objekt zu haben. In den ungewöhnlichen Fällen, in denen dies im Kontext eines Algorithmus keinen Sinn ergibt, bieten die meisten Sprachen die Möglichkeit, einen "Klon" oder eine tiefe Kopie zu erstellen. Dies ist jedoch nicht die Standardeinstellung.
Ich denke, Leute, die argumentieren, dass dies nicht der Standard sein sollte, verwenden eine Sprache, die keine automatische Speicherbereinigung bietet. Zum Beispiel altmodisches C ++. Das Problem dabei ist, dass sie einen Weg finden müssen, um "tote" Objekte zu sammeln und keine Objekte zurückzugewinnen, die möglicherweise noch benötigt werden. Mehrere Verweise auf dasselbe Objekt machen dies schwierig.
Ich denke, wenn C ++ eine ausreichend kostengünstige Garbage Collection hätte, so dass alle referenzierten Objekte Garbage Collected sind, dann verschwindet ein Großteil der Einwände. Es wird immer noch Fälle geben, in denen die Referenzsemantik nicht erforderlich ist. Nach meiner Erfahrung sind die Personen, die diese Situationen identifizieren können, jedoch in der Regel auch in der Lage, die entsprechende Semantik zu wählen.
Ich glaube, es gibt Hinweise darauf, dass ein großer Teil des Codes in einem C ++ - Programm dazu dient, die Garbage Collection zu handhaben oder zu mildern. Das Schreiben und Verwalten dieser Art von "Infrastruktur" -Code verursacht jedoch zusätzliche Kosten. Es ist dazu da, die Sprache benutzerfreundlicher oder robuster zu machen. So wurde beispielsweise die Sprache Go mit dem Schwerpunkt entwickelt, einige der Schwächen von C ++ zu beheben, und es bleibt keine andere Wahl als die Garbage Collection.
Dies ist im Kontext von Java natürlich irrelevant. Es wurde ebenfalls so konzipiert, dass es einfach zu bedienen ist, ebenso wie die Garbage Collection. Daher ist das Vorhandensein mehrerer Referenzen die Standard-Semantik und in dem Sinne relativ sicher, dass Objekte nicht zurückgefordert werden, solange eine Referenz auf sie vorhanden ist. Natürlich könnten sie von einer Datenstruktur festgehalten werden, da das Programm nicht richtig aufräumt, wenn es wirklich mit einem Objekt fertig ist.
Wenn Sie sich also (mit ein wenig Verallgemeinerung) wieder Ihrer Frage widmen, wann möchten Sie mehr als einen Verweis auf dasselbe Objekt? So ziemlich in jeder Situation, die mir einfällt. Sie sind die Standardsemantik der meisten Übergabemechanismen für Sprachparameter. Ich schlage vor, das liegt daran, dass die Standardsemantik für den Umgang mit Objekten, die in der realen Welt vorhanden sind, so gut wie per Referenz festgelegt werden muss (weil die tatsächlichen Objekte da draußen sind).
Jede andere Semantik wäre schwieriger zu handhaben.
Ich schlage vor, dass der "Rover"
dl
derjenige sein sollte, der vonsetOwner
Programmen ausgeführt wird oder der schwer zu schreiben, zu verstehen, zu debuggen oder zu modifizieren ist. Ich denke, die meisten Programmierer wären sonst verwirrt oder bestürzt.später wird der Hund verkauft:
Diese Art der Verarbeitung ist üblich und normal. Daher ist die Referenzsemantik die Standardeinstellung, da sie normalerweise am sinnvollsten ist.
Zusammenfassung: Es ist immer sinnvoll, mehrere Referenzen auf dasselbe Objekt zu haben.
quelle
Natürlich ein weiteres Szenario, in dem Sie möglicherweise Folgendes erleben:
ist, wenn Sie Code pflegen und
b
früher ein anderer Hund oder eine andere Klasse waren, aber jetzt von betreut werdena
.Im Allgemeinen sollten Sie mittelfristig den gesamten Code überarbeiten, um
a
direkt darauf zu verweisen. Dies kann jedoch nicht sofort geschehen.quelle
Sie möchten dies immer dann, wenn Ihr Programm die Möglichkeit hat, eine Entität an mehr als einer Stelle in den Speicher zu ziehen, möglicherweise weil verschiedene Komponenten sie verwenden.
Identity Maps lieferten einen endgültigen lokalen Speicher von Entitäten, sodass wir vermeiden können, zwei oder mehr separate Darstellungen zu haben. Wenn wir dasselbe Objekt zweimal darstellen, besteht für unseren Client das Risiko, dass ein Nebenläufigkeitsproblem auftritt, wenn eine Referenz des Objekts die Statusänderungen beibehält, bevor die andere Instanz dies tut. Die Idee ist, dass wir sicherstellen möchten, dass unser Kunde immer den endgültigen Verweis auf unsere Entität / Objekt behandelt.
quelle
Ich habe dies beim Schreiben eines Sudoku-Lösers verwendet. Wenn ich bei der Verarbeitung von Zeilen die Nummer einer Zelle kenne, soll die übergeordnete Spalte bei der Verarbeitung von Spalten auch die Nummer dieser Zelle kennen. Daher sind sowohl Spalten als auch Zeilen Arrays von überlappenden Zellenobjekten. Genau wie die akzeptierte Antwort zeigte.
quelle
In Webanwendungen können Object Relational Mappers das verzögerte Laden verwenden, sodass alle Verweise auf dasselbe Datenbankobjekt (zumindest innerhalb desselben Threads) auf dasselbe verweisen.
Wenn Sie beispielsweise zwei Tabellen hatten:
Hunde:
Besitzer:
Es gibt verschiedene Ansätze, die Ihr ORM ausführen kann, wenn folgende Anrufe getätigt werden:
In der naiven Strategie werden bei allen Aufrufen der Modelle und den zugehörigen Referenzen separate Objekte abgerufen.
Dog.find()
,Owner.find()
,owner.dogs
, Unddog.owner
Ergebnis in einer Datenbank traf beim ersten Mal, nach dem sie in dem Speicher gespeichert werden. Und so:Ohne Referenz haben Sie mehr Abrufe, benötigen mehr Speicher und können frühere Aktualisierungen überschreiben.
Angenommen, Ihr ORM weiß, dass alle Verweise auf Zeile 1 der Hundetabelle auf dasselbe verweisen sollten. Dann:
Mit anderen Worten, die Verwendung von Referenzen hilft dabei, das Prinzip eines einzelnen Wahrheitspunkts (zumindest innerhalb dieses Threads) als Zeile in der Datenbank zu kodieren.
quelle