Language

IFreezable インターフェイス

定義

クラスを不変にする必要なく、アクセスを制御するための柔軟なメカニズムを提供します。

[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
派生
属性
実装

注釈

クラスを不変にする必要なく、アクセスを制御するための柔軟なメカニズムを提供します。 いったん固定すると、オブジェクトをフローゼン解除することはできません。そのため、その時点からスレッド セーフになります。 オブジェクトが固定されたら、オブジェクトに変更を加えないことを保証する必要があります。 変更を試みると、UnsupportedOperationException 例外が発生する必要があります。 つまり、オブジェクトが内部オブジェクトを返すとき、または内部オブジェクトへの参照を持つユーザーがいる場合は、それらの内部オブジェクトを変更できないか、変更を試みた場合に例外を発生させる必要があります。 もちろん、オブジェクトは安全であるため、内部オブジェクトのクローンを返すことができます。 <h2>Background</h2>

多くの場合、オブジェクトを "安全" なオブジェクトにする必要があり、変更できない場合があります。 たとえば、オブジェクトをスレッド セーフにする必要がある場合や、堅牢なコードを記述する場合やキャッシュに格納する必要がある場合などです。 独自のオブジェクトのみを作成する場合は、もちろん、間違いを犯さない場合にのみ、これを保証できます。 オブジェクトを受け取った場合、または他のユーザーを使用してオブジェクトを作成している場合は、別のストーリーになります。 それはすべて、あなたがブランシュ・デュボアのアプローチを取りたいかどうかにかかっています(>見知らぬ人の親切に依存しています>)または Andy Grove のアプローチ (>唯一のパラノイドは生き残る>)。

たとえば、単純なクラスがあるとします。

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;
                 }
            }

クラスにはセッターがないため、誰かがそれが不変であると考えるかもしれません。 もちろん、これがどこをリードしているのか分かります。このクラスは、さまざまな点で安全ではありません。 次に、その例を示します。

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
             }

安全なクラスを持つには、いくつかの異なる手法があります。

<ol><li>Const オブジェクト。 C++ では、パラメーター const.< を宣言できます。/li><li>Immutable ラッパー。 たとえば、変更できないラッパーにコレクションを配置できます</li><li>Always-Immutable オブジェクト。 Javaでは、いくつかのバリエーションを使用して、このアプローチを使用します。 例: <ol><li>Simple。 Color が作成されると (たとえば、R、G、B の整数から) 変更できません。</li><li>Builder クラス。 別の 'builder' クラスがあります。 たとえば、変更可能な文字列は、StringBuffer (完全な String API を使用できない) を使用して作成されます。 変更できないフォームが必要になったら、toString().</li><li>Primitives。 これらは methods.< から入力/出力にコピーされるため、常に安全です。/li></ol></li><li>Cloning。 オブジェクトを安全にする必要がある場合は、それを複製します</li></ol>

これらのそれぞれに長所と短所があります。

<ol><li>Const は特定のレベルの保護を提供しますが、const は可能であり、多くの場合はキャストされるため、ほとんどの不注意によるミスから保護するだけです。 また、スレッド保護も提供されません。別のスレッド内の(最も無い) オブジェクトへのポインターを持っている人は誰でもあなたを混乱させる可能性があるためです</li><li>Immutable ラッパーは const よりも安全です。constness をキャストすることはできません。 ただし、他のユーザーが元のオブジェクトを保持している場合や、クラスから返されたオブジェクトのいずれかが mutable である場合は安全ではありません。ただし、同じ問題がすべて発生します。</li><li>Always-Immutable オブジェクトは安全ですが、使用するには過剰なオブジェクトの作成が必要な場合があります。</li><li>Cloning は、オブジェクトに本当に '安全な' クローンがある場合にのみ安全です。複製 に対する変更が元の複製に影響を与えないことを保証する複製として定義されます。 残念ながら、多くのオブジェクトには "安全な" クローンがなく、常に複製するには過剰なオブジェクトの作成が必要な場合があります</li></ol><h2>Freezable Model</h2>

Freezable モデルは、さまざまなメソッドを呼び出してオブジェクトを構築する機能を提供することで、これらの選択肢を補完します。その後、最終的な状態になったら、変更不可にすることができます。 変更できないと、オブジェクトを 変更することはできず 、完全にスレッド セーフになります。つまり、複数のスレッドが同期なしで参照できます。 変更可能なバージョンのオブジェクトが必要な場合は、 cloneAsThawed()を使用してコピーを変更できます。 これにより、代替手段が不十分または不十分な状況で、安全なクラスに簡単で効果的なメカニズムが提供されます。 (オブジェクトが不変になる前に共有されている場合、(他のオブジェクトと同様に) 使用をミューテックスするのは各スレッドの責任です)。

オブジェクトの種類に応じて、このインターフェイスを実装するために行う必要がある操作を次に示します。

<h3><b>Immutable Objects</b></h3>

これらは最も簡単です。 インターフェイスを使用してこれを反映するには、次のコードを追加します。

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; }
              }

変更できないオブジェクトのサブクラス自体が不変である必要があるため、これらは最終的なメソッドになる可能性があります。 (注: freeze はチェーン用の this を返します)。

<h3><b>Mutable Objects</b></h3>

保護された 'フラグ' フィールドを追加します。

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

次のメソッドを追加します。

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

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

新しい複製にcloneAsThawed()点を除き、clone()の通常のパターンに従ってfrozen=falseメソッドを追加します。

次に、セッター (つまり、オブジェクトの内部状態を変更できる任意のメソッド) を取得し、最初のステートメントとして次を追加します。

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

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

Freezableのサブクラスは、スーパークラスのフラグフィールドを使用するだけです。 スーパークラスを呼び出すには、 freeze() と cloneAsThawed() をオーバーライドする必要がありますが、通常は isFrozen()をオーバーライドしません。 その後、独自のゲッター、セッター、フィールドに注意を払う必要があります。

<h4><b>Internal Caches</b></h4>

内部キャッシュは、オブジェクトが論理的に変更されていないが、オブジェクトの内部状態が変化する場合です。 たとえば、> の const をキャストする const C++ 関数があります。this>オブジェクト キャッシュを変更するためのポインター。 これらのケースは、スレッドセーフを確保するために内部キャッシュをミューテックスすることによって処理されます。 たとえば、UnicodeSet に最後にアクセスしたコード ポイントの内部マーカーがあるとします。 この場合、フィールドは外部に表示されないため、必要なのはスレッド セーフのためにフィールドを同期することだけです。

<h4>安全な内部アクセス</h4>

内部フィールドは、または不変 (文字列やプリミティブなど) である場合にfrozenと呼ばれます。 これらに対する内部アクセスを許可したことがない場合は、すべて完了です。 たとえば、UnicodeSet を Freezable に変換するには、上記の手順を実行します。 ただし、getter、setter、またはコンストラクターに次のようなコードがある場合<>b<have>/bは安全でない内部へのアクセスを許可したことを覚えておいてください。

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

これらは、上記の <b>Background</b> のコード サンプルにも示されています。

安全でない内部に対処するには、 freeze() 関数で作業を行うのが最も簡単です。 すべての内部フィールドを固定し、固定フラグを設定するだけです。 後続のゲッター/セッターは正常に動作します。 例を次に示します。

<b>Warning!</b> 'frozen' ブール値は揮発性である必要があり、メソッドの最後のステートメントとして設定する必要があります。

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

フィールドが Collection または Mapの場合、固定するには、2 つの選択肢があります。 オブジェクトの外部からコレクションへのアクセスを許可したことがない場合は、後で変更されないようにラップするだけです。

zone_to_country = Collections.unmodifiableMap(zone_to_country);

アクセスを許可 したことがある 場合は、ラップする前に clone() を実行します。

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

コレクション (またはオブジェクトの他のコンテナー) 自体に変更可能なオブジェクトを含めることができる場合、安全な複製を作成するには、コレクション全体を変更不可にするためにそれを繰り返す必要があります。 再帰コードでは、後でダウンケースする必要がないように、使用可能な最も具体的なコレクションを選択する必要があります。

<blockquote>

<b>Note: </b>Javaの厄介な欠陥は、MapやSetなどのジェネリック コレクションにclone()操作がないということです。 コレクションの種類がわからない場合、最も簡単なコースは、新しいコレクションを作成することです。

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

</blockquote>

Javaドキュメント。

このページの一部は、によって作成および共有され、に記載されている条件に従って使用される作業に基づく変更です。

プロパティ

名前 説明
Handle

基になる Android オブジェクトの JNI 値を取得します。

(継承元 IJavaObject)
IsFrozen

オブジェクトが固定されているかどうかを判断します。

JniIdentityHashCode

ラップされたインスタンスの java.lang.System.identityHashCode() の値を返します。

(継承元 IJavaPeerable)
JniManagedPeerState

マネージド ピアの状態。

(継承元 IJavaPeerable)
JniObjectReferenceControlBlock

クラスを不変にする必要なく、アクセスを制御するための柔軟なメカニズムを提供します。

(継承元 IJavaPeerable)
JniPeerMembers

メンバー アクセスと呼び出しのサポート。

(継承元 IJavaPeerable)
PeerReference

ラップされたJava オブジェクト インスタンスのJniObjectReferenceを返します。

(継承元 IJavaPeerable)

メソッド

名前 説明
CloneAsThawed()

複製操作を提供します。

Disposed()

インスタンスが破棄されたときに呼び出されます。

(継承元 IJavaPeerable)
DisposeUnlessReferenced()

このインスタンスへの未処理の参照がない場合は、 Dispose()を呼び出します。それ以外の場合は何も実行しません。

(継承元 IJavaPeerable)
Finalized()

インスタンスが終了したときに呼び出されます。

(継承元 IJavaPeerable)
Freeze()

オブジェクトを固定します。

SetJniIdentityHashCode(Int32)

JniIdentityHashCodeによって返される値を設定します。

(継承元 IJavaPeerable)
SetJniManagedPeerState(JniManagedPeerStates)

クラスを不変にする必要なく、アクセスを制御するための柔軟なメカニズムを提供します。

(継承元 IJavaPeerable)
SetPeerReference(JniObjectReference)

PeerReferenceによって返される値を設定します。

(継承元 IJavaPeerable)
UnregisterFromRuntime()

ランタイムが将来の Java.Interop.JniRuntime+JniValueManager.PeekValue 呼び出しから返されないように、このインスタンスの登録を解除します。

(継承元 IJavaPeerable)

拡張メソッド

名前 説明
GetJniTypeName(IJavaPeerable)

インスタンス selfの型の JNI 名を取得します。

JavaAs<TResult>(IJavaPeerable)

selfを強制的にTResult入力し、強制型がJava側で有効であることを確認します。

JavaCast<TResult>(IJavaObject)

Android ランタイムチェック型変換を実行します。

JavaCast<TResult>(IJavaObject)

クラスを不変にする必要なく、アクセスを制御するための柔軟なメカニズムを提供します。

TryJavaCast<TResult>(IJavaPeerable, TResult)

selfを強制的にTResult入力し、強制型がJava側で有効であることを確認します。

適用対象