Javaのクラスインバリアントとは何ですか?


93

私はそのトピックをグーグルで検索しましたが、ウィキペディア以外に、これ以上役立つドキュメントや記事は見つかりませんでした。

誰かが私にそれが何を意味するのかを簡単な言葉で説明したり、素敵で理解しやすいドキュメントを私に紹介したりできますか?


2
質問の+1です。ウィキペディアのページには、あなたが何ができるかわからなかった素晴らしい例があります。例さえあります。彼らの説明は私があなたのためにできるよりも良いです。とても簡単です。
iandisme 2012年


Javaに関する不変条件に興味がある場合は、Javaの契約に興味があるかもしれません。
マイクサミュエル

回答:


91

特にJavaに関しては何も意味しません。

クラス不変は、他のコードが何をするかに関係なく、常にクラスのすべてのインスタンスを保持するプロパティです。

例えば、

class X {
  final Y y = new Y();
}

Xには、yプロパティがあるという不変のクラスがあり、プロパティはなくnull、typeの値を持っていますY

class Counter {
  private int x;

  public int count() { return x++; }
}

2つの重要な不変条件を維持できない

  1. それはcount可能性があるため、アンダーフローのマイナスの値を返すことはありません。
  2. の呼び出しcountは厳密に単調に増加しています。

変更されたクラスは、これらの2つの不変条件を保持します。

class Counter {
  private int x;

  public synchronized int count() {
    if (x == Integer.MAX_VALUE) { throw new IllegalStateException(); }
    return x++;
  }
}

ただし、例外をスローしたり、デッドロックされたスレッドがカウンターのモニターを所有している場合はブロックしたりするため、呼び出しがcount常に正常に成功する(TCB違反がない場合)不変条件を維持できcountません。

クラスを持つ各言語により、一部のクラスの不変式を維持し、他のクラスを維持することが容易になります。Javaも例外ではありません。

  1. Javaクラスには常にプロパティとメソッドがある場合とない場合があるため、インターフェースの不変条件の保守は簡単です。
  2. Javaクラスはprivateフィールドを保護できるため、プライベートデータに依存する不変条件の管理は簡単です。
  3. Javaクラスは最終的なものになる可能性があるため、悪意のあるサブクラスを作成することによって不変条件に違反するコードがないことに依存する不変条件を維持できます。
  4. Javaではnull、さまざまな方法で値が入り込むことができるため、「実際の値を持っている」不変条件を維持することは困難です。
  5. Javaにはスレッドがあります。つまり、同期しないクラスは、一緒に発生するスレッドでの逐次操作に依存する不変条件の維持に問題があります。
  6. Javaには例外があり、「プロパティpで結果を返すか、結果を返さない」などの不変条件を簡単に維持できますが、「常に結果を返す」などの不変条件を維持することは困難です。

†- 外部性またはTCB違反は、システム設計者が楽観的に発生しないと想定するイベントです。

通常、基本的なハードウェアは、その上に構築された高水準言語のプロパティについて話すときに宣伝どおりに機能することを信頼します。不変条件が保持する私たちの引数は、以下の可能性を考慮していません。

  • デバッグフックを使用して、プログラムでは実行できない方法でローカル変数を変更するプログラマー。
  • ピアはsetAccessibleprivateルックアップテーブルを変更するためにリフレクションを使用しません。
  • Lokiが物理を変更し、プロセッサーが2つの数値を誤って比較する原因となります。

一部のシステムでは、TCBにシステムの一部しか含まれていない場合があるため、

  • 管理者または特権デーモンは、JVMプロセスを強制終了しません。

しかし、私たちはそれを仮定するかもしれません

  • 信頼できるトランザクションファイルシステムにチェックポイントを設定できます。

システムのレベルが高いほど、そのTCBは通常大きくなりますが、TCBから得られる信頼性の低いものほど、不変条件が保持される可能性が高くなり、システムの長期的な信頼性が高まります。


1
count同じ値を2度返すことはない」というのは、本当にクラス不変と見なされますか?
ruakh

@ruakh、それは良い質問です。私はあまりよく分からない。hashCodeの安定性(インスタンスiごとに、i.hashCode()は変更されない)などは、多くの場合、以前に返された値についての推論を必要とするクラス不変式と呼ばれるため、「各インスタンスi、i.count()について、ない(以前のi.count()の結果) "はクラス不変です。
マイクサミュエル

@ruakhそれは純粋な定義ではないですか?そのような不変量を仮定するとしたら、どうしてですか?これは確かに興味深い重要な保証になる可能性があります(たとえば、一意のIDを生成するため)。個人的には「シングルスレッドコードのみがこのクラスにアクセスする場合、次のプロパティが保持される」のようなものも有用だと思いますが、特定の期間だけ保持する必要があるように定義を拡張できるかどうかはわかりません条件は真です。(そして、反射を考えると、それ以外の興味深いものを保証することは基本的に不可能です!)
Voo

1
@ruakh-クラス不変式またはメソッド不変式としてモデル化できます。いずれにしても、それをモデル化するには、特定のオブジェクトに対するメソッドへの以前の呼び出しの概念的な履歴が必要です。実際、これをメソッドの事後条件としてモデル化することもできます。つまり、結果の値は以前に返されたことがないものです。
スティーブンC

@Voo:Re:「それは純粋な定義ではないのですか?」可能な限り、明確な例を使用するか、明確ではない状況の事例を明示的に呼び出すことが望ましいと思われます。(ちなみに、私はこの例に積極的に反対しているわけではありません。驚いただけで、確認するために尋ねていました。)
ruakh

20

不変とは、どんな変化があっても、誰がそれを使用/変換しても、その条件に固執する必要があるものを意味します。つまり、クラスのプロパティは、パブリックメソッドを使用して変換を行った後でも、常に何らかの条件を満たします。したがって、このクラスのクライアントまたはユーザーは、クラスとそのプロパティについて保証されます。

例えば、

  1. 関数の引数の条件は、常に> 0(ゼロより大きい)であるか、またはnullであってはなりません。
  2. アカウントクラスのminimum_account_balanceプロパティは、100を下回ることはできません。したがって、すべてのパブリック関数はこの条件を尊重し、クラスが不変であることを確認する必要があります。
  3. 変数間のルールベースの依存関係、つまり、ある変数の値は別の変数に依存するため、ある修正ルールを使用して1つの変数が変更された場合、他の変数も変更する必要があります。2つの変数間のこの関係は維持する必要があります。そうでない場合は、不変式に違反しています。

11

これらは、インスタンスクラスについて真実でなければならない事実です。たとえば、クラスにプロパティXがあり、インバリアントがXは0より大きい必要がある場合があります。私の知る限り、インバリアントを維持するための組み込みメソッドはありません。プロパティをプライベートにして、ゲッターとセッターがインバリアンスプロパティを適用することを確認する必要があります。

リフレクションとインターセプターを使用してプロパティをチェックできるアノテーションが利用可能です。 http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.