Sprache

IFreezable Schnittstelle

Definition

Bietet einen flexiblen Mechanismus zum Steuern des Zugriffs, ohne dass eine Klasse unveränderlich sein muss.

[Android.Runtime.Register("android/icu/util/Freezable", "", "Android.Icu.Util.IFreezableInvoker", ApiSince=24)]
[Java.Interop.JavaTypeParameters(new System.String[] { "T" })]
public interface IFreezable : IDisposable, Java.Interop.IJavaPeerable, Java.Lang.ICloneable
[<Android.Runtime.Register("android/icu/util/Freezable", "", "Android.Icu.Util.IFreezableInvoker", ApiSince=24)>]
[<Java.Interop.JavaTypeParameters(new System.String[] { "T" })>]
type IFreezable = interface
    interface ICloneable
    interface IJavaObject
    interface IDisposable
    interface IJavaPeerable
Abgeleitet
Attribute
Implementiert

Hinweise

Bietet einen flexiblen Mechanismus zum Steuern des Zugriffs, ohne dass eine Klasse unveränderlich sein muss. Sobald eingefroren ist, kann ein Objekt niemals unfrozen sein, sodass es von diesem Zeitpunkt an threadsicher ist. Nachdem das Objekt fixiert wurde, muss sichergestellt werden, dass keine Änderungen daran vorgenommen werden können. Jeder Versuch, ihn zu ändern, muss eine Ausnahme "UnsupportedOperationException" auslösen. Dies bedeutet, dass, wenn das Objekt interne Objekte zurückgibt oder wenn jemand Verweise auf diese internen Objekte hat, dass diese internen Objekte entweder unveränderlich sein müssen oder auch Ausnahmen auslösen müssen, wenn versucht wird, sie zu ändern. Natürlich kann das Objekt Klonen interner Objekte zurückgeben, da diese sicher sind. <h2>Hintergrund</h2>

Es gibt häufig Situationen, in denen Objekte als "sicher" verwendet werden müssen, damit sie nicht geändert werden können. Beispiele sind, wenn Objekte threadsicher oder robusten Code oder in Caches schreiben müssen. Wenn Sie nur eigene Objekte erstellen, können Sie dies natürlich garantieren - aber nur, wenn Sie keinen Fehler machen. Wenn Sie Objekte an Sie übergeben haben oder Objekte mit anderen Personen erstellen, die Sie übergeben haben, ist dies eine andere Geschichte. Alles kommt darauf an, ob Sie den Ansatz von Blanche Dubois verfolgen möchten (" hängt von der Freundlichkeit fremder Menschen ab") oder der Andy Grove-Ansatz (" Nur das Paranoid überleben").

Angenommen, wir haben eine einfache Klasse:

public class A {
                 protected Collection b;

                 protected Collection c;

                 public Collection get_b() {
                         return b;
                 }

                 public Collection get_c() {
                         return c;
                 }

                 public A(Collection new_b, Collection new_c) {
                         b = new_b;
                         c = new_c;
                 }
            }

Da der Kurs keine Setter hat, könnte jemand denken, dass er unveränderlich ist. Sie wissen, wo dies führt, natürlich; diese Klasse ist auf verschiedene Arten unsicher. Dies wird im Folgenden veranschaulicht.

public test1(SupposedlyImmutableClass x, SafeStorage y) {
               // unsafe getter
               A a = x.getA();
               Collection col = a.get_b();
               col.add(something); // a has now been changed, and x too

               // unsafe constructor
               a = new A(col, col);
               y.store(a);
               col.add(something); // a has now been changed, and y too
             }

Es gibt ein paar verschiedene Techniken für die Verwendung sicherer Klassen.

<ol><li>Const-Objekte. In C++ können Sie Parameter konst deklarieren.</li li><>Unveränderliche Wrapper. Sie können beispielsweise eine Auflistung in einen unveränderlichen Wrapper einfügen.</li li><>Always-Immutable Objekte. Java verwendet diesen Ansatz mit einigen Variationen. Beispiele: <ol><li>Simple. Sobald eine Farbe erstellt wurde (z. B. aus R, G und B ganze Zahlen), ist sie unveränderlich.</li li><>Builder Class. Es gibt eine separate "Generator"-Klasse. Beispielsweise werden modifizierbare Zeichenfolgen mithilfe von StringBuffer erstellt (die nicht die vollständige Zeichenfolgen-API verfügbar ist). Sobald Sie ein unveränderliches Formular wünschen, erstellen Sie ein Formular mit toString().</li li><>Grundtypen. Diese sind immer sicher, da sie in Eingabe-/Ausgabe von Methoden kopiert werden.</li></ol></li li li><>Cloning. Wo ein Objekt sicher sein muss, klonen Sie es.</li></ol>

Es gibt Vor- und Nachteile jeder dieser.

<ol><li>Const bietet ein gewisses Maß an Schutz, aber da const kann und oft weggeworfen wird, schützt es nur vor den meisten versehentlichen Fehlern. Es bietet auch keinen Threadingschutz, da jeder, der über einen Zeiger auf das (unkonst)-Objekt in einem anderen Thread verfügt, Sie verwöhnen kann.</li li><>Unveränderliche Wrapper sind sicherer als Konst, da die Konstness nicht weggeworfen werden kann. Außer dass sie alle gleichen Probleme haben: nicht sicher, wenn eine andere Person das ursprüngliche Objekt aufbewahrt, oder wenn eines der von der Klasse zurückgegebenen Objekte änderbar ist.</li li><>Always-Immutable Objekte sind sicher, die Verwendung kann jedoch eine übermäßige Objekterstellung erfordern.</li li><>Cloning ist nur sicher, wenn das Objekt wirklich über einen "sicheren" Klon verfügt; definiert als ein Klon, der sicherstellt, dass sich keine Änderung am Klon auf das Original auswirkt. Leider verfügen viele Objekte nicht über einen "sicheren" Klon, und das Klonen kann immer eine übermäßige Objekterstellung erfordern.</li></ol><h2>Freezable Model</h2>

Das Freezable Modell ergänzt diese Auswahl, indem Sie ihnen die Möglichkeit geben, ein Objekt durch Aufrufen verschiedener Methoden aufzubauen, und wenn es sich in einem endgültigen Zustand befindet, können Sie es unveränderlich machen . Sobald unveränderlich, kann ein Objekt nicht mehr geändert werden und ist vollständig threadsicher: d. h. mehrere Threads können ohne Synchronisierung Verweise darauf haben. Wenn jemand eine änderbare Version eines Objekts benötigt, kann er die Kopie verwenden cloneAsThawed()und ändern. Dies bietet einen einfachen, effektiven Mechanismus für sichere Klassen in Situationen, in denen die Alternativen unzureichend oder unblänglich sind. (Wenn ein Objekt freigegeben wird, bevor es unveränderlich ist, liegt es in der Verantwortung jedes Threads, seine Verwendung (wie bei anderen Objekten) stummzuschalten.)

Hier ist, was erforderlich ist, um diese Schnittstelle zu implementieren, je nach Typ des Objekts.

<h3><b>unveränderliche Objekte</b></h3>

Dies sind die einfachsten. Sie verwenden einfach die Schnittstelle, um dies widerzuspiegeln, indem Sie Folgendes hinzufügen:

public class A implements Freezable&lt;A&gt; {
              ...
              public final boolean isFrozen() {return true;}
              public final A freeze() {return this;}
              public final A cloneAsThawed() { return this; }
              }

Dies kann abschließende Methoden sein, da Unterklassen von unveränderlichen Objekten selbst unveränderlich sein müssen. (Hinweis: freeze wird für Verkettung zurückgegeben this .)

<h3><b>mutierbare Objekte</b></h3>

Fügen Sie ein geschütztes Feld "Flagging" hinzu:

protected volatile boolean frozen; // WARNING: must be volatile

Fügen Sie die folgenden Methoden hinzu:

public final boolean isFrozen() {
                 return frozen;
            };

            public A freeze() {
                 frozen = true;  // WARNING: must be final statement before return
                 return this;
            }

Fügen Sie eine cloneAsThawed() Methode nach dem normalen Muster hinzu clone(), mit der Ausnahme, dass frozen=false im neuen Klon.

Nehmen Sie dann die Setter (d. a. jede Methode, die den internen Zustand des Objekts ändern kann), und fügen Sie Folgendes als erste Anweisung hinzu:

if (isFrozen()) {
                 throw new UnsupportedOperationException(&quot;Attempt to modify frozen object&quot;);
            }

<h4><b>Subclassing</b></h4>

Jede Unterklasse einer Freezable Klasse verwendet nur das Flaggingfeld der Superklasse. Sie muss die Superklasse überschreiben freeze() und cloneAsThawed() aufrufen, aber normalerweise nicht überschreiben isFrozen(). Es muss dann nur auf seine eigenen Getters, Setter und Felder achten.

<h4><b>Interne Caches</b></h4>

Interne Caches sind Fälle, in denen das Objekt logisch unverändert ist, aber der interne Zustand des Objekts geändert wird. Es gibt z. B. C++-Funktionen, die den Const für das " this" Zeiger zum Ändern eines Objektcaches. Diese Fälle werden durch Stummschalten des internen Caches behandelt, um die Threadsicherheit zu gewährleisten. Angenommen, UnicodeSet hatte einen internen Marker für den letzten Codepunkt, auf den zugegriffen wurde. In diesem Fall ist das Feld nicht extern sichtbar, daher müssen Sie nur das Feld für threadsicherheit synchronisieren.

<h4>Unsicherer interner Zugriff</h4>

Interne Felder werden als sicher bezeichnet, wenn sie entweder frozen oder unveränderlich sind (z. B. Zeichenfolge oder Grundtypen). Wenn Sie nie internen Zugriff auf diese erlaubt haben, sind Sie fertig. Beispielsweise erfolgt die Konvertierung von UnicodeSet Freezable in die oben genannten Schritte. Denken Sie aber daran, dass Sie <b>/<b> Zugriff auf unsichere Interne haben, wenn Sie Code wie die folgenden haben, in einem Getter, Setter oder Konstruktor:

Collection getStuff() {
                 return stuff;
            } // caller could keep reference &amp; modify

            void setStuff(Collection x) {
                 stuff = x;
            } // caller could keep reference &amp; modify

            MyClass(Collection x) {
                 stuff = x;
            } // caller could keep reference &amp; modify

Diese werden auch im Codebeispiel in <b>Background</b> oben veranschaulicht.

Um unsichere Interne zu bewältigen, besteht der einfachste Handlungsaufwand darin, die Arbeit in der freeze() Funktion auszuführen. Machen Sie einfach alle internen Felder fixiert, und legen Sie die fixierte Kennzeichnung fest. Jeder nachfolgende Getter/Setter funktioniert ordnungsgemäß. Hier ist ein Beispiel:

<b>Warnung!</b> Der boolesche Wert 'frozen' MUSS veränderlich sein und muss als letzte Anweisung in der Methode festgelegt werden.

public A freeze() {
                 if (!frozen) {
                         foo.freeze();
                         frozen = true;
                 }
                 return this;
            }

Wenn es sich bei dem Feld um ein Collection oder Map, dann um es eingefroren zu machen, haben Sie zwei Auswahlmöglichkeiten. Wenn Sie nie zugriff auf die Auflistung von außerhalb Des Objekts haben, schließen Sie sie einfach um, um zukünftige Änderungen zu verhindern.

zone_to_country = Collections.unmodifiableMap(zone_to_country);

Wenn Sie jemals Zugriff gewährt haben, führen Sie eine clone() vor dem Umbruch durch.

zone_to_country = Collections.unmodifiableMap(zone_to_country.clone());

Wenn eine Auflistung (oder ein anderer Container von Objekten) selbst veränderbare Objekte enthalten kann, müssen Sie für einen sicheren Klon, den Sie durchlaufen müssen, um die gesamte Auflistung unveränderlich zu machen. Der rekursierende Code sollte die spezifischste verfügbare Sammlung auswählen, um die Notwendigkeit einer späteren Abwärtserkennung zu vermeiden.

<Blockquote>

<b>Hinweis: </b>Ein lästiger Fehler in Java ist, dass die generischen Sammlungen wie Map oder Set, keine Operation habenclone(). Wenn Sie den Typ der Sammlung nicht kennen, besteht der einfachste Kurs darin, einfach eine neue Sammlung zu erstellen:

zone_to_country = Collections.unmodifiableMap(new HashMap(zone_to_country));

</blockquote>

Java Dokumentation für android.icu.util.Freezable.

Teile dieser Seite sind Änderungen auf der Grundlage von Arbeiten, die von der Android Open Source Project erstellt und gemeinsam verwendet und gemäß den in der 2.5 Attribution License beschriebenen Begriffen verwendet werden.

Eigenschaften

Name Beschreibung
Handle

Ruft den JNI-Wert des zugrunde liegenden Android-Objekts ab.

(Geerbt von IJavaObject)
IsFrozen

Bestimmt, ob das Objekt fixiert wurde oder nicht.

JniIdentityHashCode

Gibt den Wert java.lang.System.identityHashCode() für die umbrochene Instanz zurück.

(Geerbt von IJavaPeerable)
JniManagedPeerState

Status des verwalteten Peers.

(Geerbt von IJavaPeerable)
JniObjectReferenceControlBlock

Bietet einen flexiblen Mechanismus zum Steuern des Zugriffs, ohne dass eine Klasse unveränderlich sein muss.

(Geerbt von IJavaPeerable)
JniPeerMembers

Mitgliedszugriff und Aufrufunterstützung.

(Geerbt von IJavaPeerable)
PeerReference

Gibt eine JniObjectReference der umbrochenen Java Objektinstanz zurück.

(Geerbt von IJavaPeerable)

Methoden

Name Beschreibung
CloneAsThawed()

Stellt den Klonvorgang bereit.

Disposed()

Wird aufgerufen, wenn die Instanz verworfen wurde.

(Geerbt von IJavaPeerable)
DisposeUnlessReferenced()

Wenn keine offenen Verweise auf diese Instanz vorhanden sind, wird nichts aufgerufen Dispose(). Andernfalls wird nichts ausgeführt.

(Geerbt von IJavaPeerable)
Finalized()

Wird aufgerufen, wenn die Instanz abgeschlossen wurde.

(Geerbt von IJavaPeerable)
Freeze()

Fixiert das Objekt.

SetJniIdentityHashCode(Int32)

Legen Sie den von JniIdentityHashCode.

(Geerbt von IJavaPeerable)
SetJniManagedPeerState(JniManagedPeerStates)

Bietet einen flexiblen Mechanismus zum Steuern des Zugriffs, ohne dass eine Klasse unveränderlich sein muss.

(Geerbt von IJavaPeerable)
SetPeerReference(JniObjectReference)

Legen Sie den von PeerReference.

(Geerbt von IJavaPeerable)
UnregisterFromRuntime()

Heben Sie die Registrierung dieser Instanz auf, damit die Laufzeit sie nicht aus zukünftigen Java.Interop.JniRuntime+JniValueManager.PeekValue Aufrufen zurückgibt.

(Geerbt von IJavaPeerable)

Erweiterungsmethoden

Name Beschreibung
GetJniTypeName(IJavaPeerable)

Ruft den JNI-Namen des Typs der Instanz selfab.

JavaAs<TResult>(IJavaPeerable)

Versuchen Sie, die Eingabe selfzu TResult erzwingen, und überprüfen Sie, ob die Koersion auf der Java Seite gültig ist.

JavaCast<TResult>(IJavaObject)

Führt eine android-laufzeitgecheckte Typkonvertierung aus.

JavaCast<TResult>(IJavaObject)

Bietet einen flexiblen Mechanismus zum Steuern des Zugriffs, ohne dass eine Klasse unveränderlich sein muss.

TryJavaCast<TResult>(IJavaPeerable, TResult)

Versuchen Sie, die Eingabe selfzu TResult erzwingen, und überprüfen Sie, ob die Koersion auf der Java Seite gültig ist.

Gilt für: