Ist Guavas ImmutableXXX wirklich unveränderlich?

8

Ich benutze seit einiger Zeit Guave und vertraute ihr wirklich, bis ich gestern von einem Beispiel stolperte, das mich zum Nachdenken brachte. Lange Rede, kurzer Sinn, hier ist es:

%Vor%

Nach dem Ausführen können Sie sehen, dass sich der Wert eines Eintrags innerhalb einer ImmutableList geändert hat. Wenn hier zwei Threads beteiligt sind, könnte es passieren, dass das aktualisierte des anderen nicht angezeigt wird.

Auch die Sache, die mich sehr ungeduldig auf eine Antwort macht, ist, dass Item15 in Effective Java, Punkt fünf, folgendes sagt:

Erstellen Sie defensive Kopien im Konstruktor - was ziemlich logisch erscheint.

Betrachtet man den Quellcode der ImmutableList, sehe ich folgendes:

%Vor%

Also wird tatsächlich keine Kopie gemacht, obwohl ich keine Ahnung habe, wie eine generische tiefe Kopie in einem solchen Fall implementiert wird (kann Serialisierung sein?).

Also ... warum werden sie dann unveränderlich genannt?

    
Eugene 21.08.2012, 11:34
quelle

3 Antworten

27

Was Sie hier verstehen, ist der Unterschied zwischen unveränderlich und tief unveränderlich.

Ein unveränderliches Objekt wird sich niemals ändern, aber alles, auf das es sich bezieht, könnte sich ändern. Tiefe Unveränderlichkeit ist viel stärker: weder das Basisobjekt noch irgendein Objekt, zu dem man von navigieren kann, wird sich ändern.

Jedes ist in seinen eigenen Situationen angemessen. Wenn Sie eine eigene Klasse mit einem Feld vom Typ Date erstellen, ist dieses Datum im Besitz von für Ihr Objekt; Es ist wirklich ein Teil davon. Daher sollten Sie defensive Kopien davon machen (auf dem Weg in und den Ausweg!), Um eine tiefe Unveränderlichkeit zu erreichen.

Aber eine Sammlung "besitzt" ihre Elemente nicht wirklich. Ihre Staaten gelten nicht als Teil des Sammlungsstaats; Es ist ein anderer Typ von Klasse - ein Container . (Wie Sie bereits angedeutet haben, hat es keine genaue Kenntnis darüber, welcher Elementtyp verwendet wird, so dass er sowieso nicht weiß, wie die Elemente zu kopieren sind.)

Eine andere Antwort besagt, dass die Guava-Sammlungen den Begriff nicht änderbar verwendet haben sollten. Aber es gibt einen sehr wohl definierten Unterschied zwischen den Begriffen unmodifizierbar und unveränderlich im Zusammenhang mit Sammlungen, und es hat nichts mit oberflächlicher und tiefer Unveränderlichkeit zu tun. "Nicht änderbar" sagt, dass Sie diese Instanz nicht über die Referenz, die Sie haben, ändern können; "unveränderlich" bedeutet, dass sich diese Instanz nicht ändern kann, Punkt, ob von Ihnen oder einem anderen Akteur.

    
Kevin Bourrillion 21.08.2012, 14:08
quelle
12

Die Liste selbst ist unveränderbar, da Sie keine Elemente hinzufügen / entfernen können. Die Elemente sind hinsichtlich der Unveränderbarkeit eigenständig. Genauer gesagt haben wir Definitionen aus einem historischen Java 1.4.2-Dokument :

  
  • Sammlungen, die keine Änderungsvorgänge unterstützen (z. B. Hinzufügen, Entfernen und Löschen), werden als nicht änderbar bezeichnet. Sammlungen, die nicht unmodifizierbar sind, werden als modifizierbar bezeichnet.
  •   
  • Sammlungen, die zusätzlich garantieren, dass keine Änderung im Collection-Objekt jemals sichtbar sein wird, werden als unveränderlich bezeichnet. Sammlungen, die nicht unveränderbar sind, werden als veränderbar bezeichnet.
  •   

Beachten Sie, dass wir für diese Definitionen eine implizite Unterscheidung zwischen einer Sammlung in einem abstrakten Sinn und einem Objekt, das diese Sammlung darstellt, annehmen müssen. Dies ist wichtig, weil das Objekt, das eine unveränderbare Sammlung darstellt, nicht selbst unveränderlich ist durch eine Standarddefinition dieses Begriffs. Zum Beispiel hat seine Beziehung equals keine zeitliche Konsistenz, eine wichtige Voraussetzung für unveränderliche Objekte.

Was das defensive Kopieren betrifft, beachten Sie, dass es sich im Allgemeinen um ein schlecht definiertes Problem handelt und dass es niemals eine allgemeine unveränderliche Sammlung in Java geben wird, die ihre Elemente defensiv kopieren kann. Beachten Sie außerdem, dass eine solche Sammlung weniger nützlich als die tatsächlich vorhandenen unveränderlichen Sammlungen ist: Wenn Sie ein Objekt in eine Sammlung einfügen, möchten Sie in 99,99% Fällen genau dieses Objekt da zu sein, nicht irgendein anderes Objekt, das nicht gleich ist.

Es gibt eine ziemlich standardisierte Definition von object immutability (im Gegensatz zu collection immutability ), die transitive Unveränderlichkeit des gesamten Objektgraphen voraussetzt, das vom unveränderlichen Objekt aus erreichbar ist. Eine solche Definition wird jedoch in der realen Welt fast nie erfüllt. Zwei Beispiele dafür:

  • Nichts ist unveränderlich angesichts der Reflexion. Sogar final Felder sind beschreibbar.
  • sogar String , diese Bastillon der Unveränderlichkeit, hat sich als veränderlich erwiesen außerhalb der Java-Sandbox (ohne SecurityManager - was 99% der realen Java-Programme abdeckt).
Marko Topolnik 21.08.2012 11:37
quelle
3

Sie mischen die Unveränderlichkeit der Liste und die Unveränderlichkeit der darin enthaltenen Objekte. In einer unveränderbaren Sammlung können Sie keine Objekte hinzufügen / entfernen, aber wenn das Objekt veränderbar ist, können Sie sie ändern, nachdem get() ingiert wurde.

    
jolivier 21.08.2012 11:40
quelle