Ich habe einen Vorschlag für Werttypen in Java gelesen und bin auf diesen Satz gestoßen: "Die Objektidentität dient nur zur Unterstützung der Veränderlichkeit, wobei der Status eines Objekts mutiert werden kann, aber dasselbe intrinsische Objekt bleibt."
Soweit ich weiß (wenn auch nur vorläufig), ist Objektidentität die Idee, dass Ihre Variable als Zeiger oder Verweis auf ein Objekt fungiert, das sich an einer anderen Stelle im Speicher befindet (z. B. Objekte, die auf dem Heap in Java oder C # instanziiert wurden). Was hätte das mit Objektveränderlichkeit zu tun? Bedeutet dies, dass beispielsweise instanziierte Objekte auf dem Stapel in C ++ unveränderlich sind? Ich habe Probleme, den Link hier zu sehen.
java
c++
object-oriented
memory
immutability
Drazen Bjelovuk
quelle
quelle
struct Point {public int x,y;}
einer DeklarationPoint pt
sollten zwei Variablen mit dem Namenpt.x
und deklariert werdenpt.y
. Ein Methodenparameter vom TypPoint
sollte zweiint
Parameter sein. Unter solchen Regeln wären die einzigen Aspekte, die eine Änderung der Laufzeit erfordern würden, Arrays und Funktionsrückgabewerte. Arrays, die nurThread
, um sie zu halten.Antworten:
Bevor wir uns mit Identität befassen, definieren wir etwas genauer , was wir unter Gleichheit verstehen . Wir sagen, zwei Dinge sind genau dann gleich, wenn wir sie nicht unterscheiden können (siehe: Identität von Ununterscheidbaren ). Das heißt, ob zwei Dinge gleich sind oder nicht, hängt davon ab, wie wir sie untersuchen müssen.
Lassen Sie uns noch etwas mehr über die Programmierung nachdenken. Lassen wir unsere Vorurteile an der Tür und nehmen an, wir arbeiten in einer brandneuen unbekannten Sprache, in der alle Variablen und Werte unveränderlich sind. Nach der obigen Definition sind zwei Werte
A
undB
genau dann gleich, wenn es KEINE Programme in der Sprache gibt, die unterschiedliche Ergebnisse liefern, wennA
sie anstelle vonB
oder umgekehrt verwendet werden. Lassen Sie uns sagenA
undB
sind (IEEE 754) schwimmt, und wenn in den Ausdruck_ + 1.0
, ist das Ergebnis1.0
für beideA
undB
. SicherA
undB
sind beide Null. Sind sie gleich? Das hängt davon ab, ob die Sprache eine Funktion bietet, mit der ich das Vorzeichen der Null bestimmen kann? Wenn nicht, sind sie gleich; Wenn ja, können sie nicht sein.Daher sind zwei Werte jedes Mal gleich, wenn sie für alle möglichen Kombinationen von Operationen, die sie unterstützen, dieselben Ergebnisse liefern. Insbesondere unveränderliche Werte führen nicht zu unterschiedlichen Ergebnissen, je nachdem, welche Operationen zuvor auf sie angewendet wurden. Aus diesem Grund ist es uns egal, ob zwei Variablen auf zwei Kopien desselben Werts verweisen oder ob beide auf dieselbe Kopie verweisen.
Was hat das mit Veränderlichkeit zu tun? Veränderlichkeit impliziert, dass unsere Sprache eine Vorstellung von einer Speicherzelle hat, deren Inhalt überschrieben werden kann. Nehmen wir an, wir unterstützen unsere Sprache um veränderbare Speicherzellen:
ref <value>
erstellt eine neue Speicherzelle, die sich von allen anderen unterscheidet und auf initialisiert ist<value>
.<variable> := <value>
überschreibt den Inhalt einer Referenzzelle.!<variable>
Gibt den aktuell in einer Referenzzelle gespeicherten Wert zurück.Lassen Sie uns nun darüber nachdenken, was Gleichheit für Speicherzellen bedeutet. Angenommen,
A = ref 0
undB = A
. Betrachten Sie dieses Programm:Ersetzen Sie
A
Drucke durch den Rohling1
und ersetzen Sie auchB
Drucke1
. Nehmen wir nun anA = ref 0
undB = ref 0
. In diesem Fall Einsetzen in die obigen Programm druckt1
und0
, da jetztA
undB
zeigen Sie auf verschiedene Speicherzellen.Es ist uns also wichtig, ob zwei Referenzen auf dieselbe Speicherzelle oder auf unterschiedliche Speicherzellen verweisen. Da dies wichtig ist, wäre es nützlich, zwei Referenzen effizient und allgemein voneinander zu unterscheiden. Unsere derzeitige Methode zum Vergleichen der Werte, die sie enthalten, und wenn sie gleich mutieren, ist einer von ihnen aus mehreren Gründen problematisch:
Daher wäre es für die Sprache nützlich, eine Operation bereitzustellen, mit der direkt überprüft werden kann, ob zwei Referenzen auf dieselbe veränderbare Speicherzelle verweisen. Eine solche Funktion ist für unveränderliche Werte sinnlos; in der Tat würde ich sagen, es ist geradezu schädlich. Wenn es eine Möglichkeit
1
gab, festzustellen , ob zwei s an verschiedenen Stellen im Speicher gespeichert sind, kann es Programme geben, die sich darum kümmern, ob ich das eine1
oder das andere übergebe. Ich möchte mir wirklich keine Sorgen machen, ob ich "das Richtige1
" habe; Mathe ist schon schwer genug! Es ist also klar, dass die Überprüfung der Speichergleichheit hauptsächlich für veränderbare Typen nützlich ist.quelle
Bild Sie haben zwei Objekte zum Beispiel für Instanzen der Klasse
List
. Beide Listen haben den gleichen Inhalt. Jetzt lesen Sie die Listen und berechnen und geben etwas basierend auf ihrem Inhalt aus. Ist es wichtig, welche Liste Sie verwenden? Es liegt nicht daran, dass sie den gleichen Inhalt haben.Aber was ist, wenn eine der Listen geändert wird? Jetzt ist es tut unabhängig davon , welche Sie sich entscheiden für das Lesen und outputing etwas. Daher müssen Sie in der Lage sein, zwischen ihnen zu unterscheiden, und Sie möchten auch in bestimmten Situationen überprüfen können, ob zwei Variablen auf dasselbe Objekt (oder eine Liste hier) verweisen.
Wenn Sie jedoch den Inhalt einer Liste nicht ändern können, müssen Sie nicht einmal zwei Listenobjekte mit demselben Inhalt haben, da Sie sie sowieso nicht ändern können. Wenn Sie den Inhalt "ändern" möchten, erstellen Sie stattdessen ein neues Listenobjekt mit anderem Inhalt - wie gesagt ein neues Objekt. Unter diesem Gesichtspunkt spielt die Identität also keine Rolle. Nur der Inhalt funktioniert und nur der Inhalt sollte zum Vergleichen von zwei Listen verwendet werden.
Beachten Sie auch, dass der Compiler auf dasselbe Listenobjekt verweisen kann, selbst wenn Sie zwei Objekte deklarieren, da er seinen Inhalt nur einmal speichern muss, da er sich nicht ändern kann.
quelle
Die Objektidentität existiert nicht "nur", um die Veränderlichkeit zu unterstützen, sondern hat auch andere Verwendungszwecke [tatsächlich ist eine Instanz des
Object
Typs nur als Identitätstoken nützlich, da sie keinerlei beobachtbar veränderbare Attribute hat!] Stattdessen ist Identität häufig - Unerwünschte Eigenschaft, die ein veränderliches Objekt erhält, wenn mehrere Verweise auf das Objekt vorhanden sind. Sie werden nicht alle von einem einzelnen Eigentümer gesteuert, und Entitäten außerhalb des Eigentümers können - ohne Wissen des Eigentümers - Änderungen an diesem Objekt vornehmen oder sehen .Angenommen, ein statisches Feld
X
enthält einen Verweis auf eine Einzelelementinstanz vonint[]
und X [0] = 5. Das statische Feld enthältY
auch ein Element für eine Einzelelementinstanz vonint[]
und Y [0] = 5. Wenn Code jemals ruftIdentityHashCase()
anX
undY
, oder , wenn Code - TestsX==Y
, wird es in der Lage sein , ob zu erkennenX
undY
die gleiche Instanz zu identifizierenint[]
oder verschiedene Instanzen. Ebenso, wenn Code so etwas wie tutX[0]+=1; Y[0]+=2;
, wird das Verhalten davon abhängen , obX
undY
die gleiche Instanz oder verschiedene Instanzen identifizieren. Wenn der Code jedoch niemals die Referenzgleichheit prüftX
undY
explizit überprüft oder seinen Identitäts-Hash-Code überprüft oder irgendetwas anderes "referenzbezogen" tut, und wennX[0]
undY[0]
werden dann nie geändertX
undY
sind gleichwertig, unabhängig davon, ob sie dieselben oder unterschiedliche Arrays identifizieren.Eines der unangenehmen Dinge an der Identität in Java oder .NET ist, dass die Identität eines Objekts im Wesentlichen vom Aufenthaltsort jeder Entität im Universum abhängt, die möglicherweise Änderungen an diesem Objekt vornimmt oder sieht. Wenn ein Verweis auf ein Objekt jemals frei externem Code ausgesetzt ist, verliert der Eigentümer des Objekts die Kontrolle darüber und kann es niemals zurückerhalten.
Werttypen können im Gegensatz zu Objekten nur durch das Objekt oder die Methode, in der sie deklariert sind, beobachtet oder geändert werden. Ein Objekt, das ein Feld vom Werttyp enthält, muss sich also keine Sorgen machen, die Kontrolle darüber zu verlieren, da dies semantisch unmöglich ist. In .NET (wenn auch nicht in Java) ist es möglich, eine Variable, ein Feld, ein Array-Element oder einen anderen Speicherort als "Referenzparameter" zu übergeben. Dadurch wird vorübergehend die Methode zu beobachten oder zu ändern , den Inhalt des übergebenen Lagerort für die Dauer seiner Ausführung erlauben, aber jede bestanden „byref“ (der Fachbegriff für das, was passiert ist) gewährleistet ist, bevor die Methode zurückkehrt , zerstört werden, Dadurch wird sichergestellt, dass der Anrufer die Kontrolle über die darin gespeicherten Daten behält.unerwünschte Identität.
quelle
Object
Hat in Java ein sehr wichtiges veränderliches Attribut, den damit verbundenen gegenseitigen Ausschluss!Object
Identitätstoken verwendet. In dem Maße, wie sie als Kapselung eines veränderlichen Zustands in einem Objekt angesehen werden, gibt es kein unveränderliches Objekt. Es ist ironisch, dass Java manchmal als "Unterrichtssprache" angesehen wird, da ein wichtigeres Entwurfsziel darin bestand, die Laufzeit durch Verwendung eines einzigen Referenztyps zu vereinfachen. Aus semantischer Sicht wäre es besser gewesen, Typen mit einer Identität von solchen ohne Identität zu unterscheiden. Dernew String("Hello");
als Schlüssel in a verwendet wirdIdentityHashMap
, sieht die Zeichenfolge wie jede andere Zeichenfolge aus, die diese Zeichen in Code einkapselt, der diese Zuordnung nicht kennt, sie kann jedoch nicht ersetzt werden, da das zugrunde liegende Objekt über ein Identitätstoken verfügt unterscheidet sich von jedem anderen Objekt im gesamten Universum.Object
. Jede Definition der Unveränderlichkeit auf Klassenebene, die z. B. erfülltInteger
würde, würde gleichermaßen erfüllt sein durchObject
. Wenn ein Objekt einen veränderlichen Zustand einkapseln soll, ist es im Allgemeinen möglich, diesen Zustand sinnvoll von einer Instanz in eine andere zu kopieren. Ich glaube nicht, dass es eine Möglichkeit gibt, den Sperrstatus eines Objekts in ein anderes zu kopieren.