3

Blochは、 Effective Javaで、オブジェクトを不変にするためにすべてのフィールドを final にすることを推奨しています。

そうする必要がありますか?アクセサーメソッドを指定しないだけで不変になるわけではありません。

例えば

class A {
      private int x;
      A (int x) {
          this.x = x;
      }
}

x上記のクラスは、正しいと宣言しなくても不変finalですか? 何か不足していますか?

4

7 に答える 7

6

@Bozhoのポイントに加えて、フィールドを宣言するfinalことは、同期なしで安全にアクセスできることを意味します。

対照的に、フィールドが存在しない場合、final別のスレッドが適切な同期なしでフィールドにアクセスすると、フィールドの異常な値が表示されるリスクがわずかにあります。これは、オブジェクトの構築後にフィールドの値を変更しない場合でも発生する可能性があります。

于 2011-09-29T13:49:46.357 に答える
5

値を変更できるため、「完全に」不変ではありません。次は、チームの他の誰かがフィールドに新しい値を割り当てます。final不変性の意図を示します。

于 2011-09-29T13:45:36.313 に答える
3

Java Concurrency In Practiceで用語が定義されているように、クラスは「事実上不変」です。

これは、インスタンスへの参照が「安全に公開」されている限り、それらは不変であることを意味します。参照を安全に公開するには、同期を使用して、Java メモリ モデル (JMM) が、呼び出し元が完全に書き込まれたフィールドの値を確認できることを保証できるようにする必要があります。たとえば、フィールドが final ではなく、インスタンスが構築されて別のスレッドに渡された場合、他のスレッドはそのフィールドを未定義の状態 (nullオブジェクト参照であるか、64 ビットlongフィールドの半分のみであるかなど) で見る可能性があります。 )。

インスタンスが単一のスレッドでのみ使用される場合、区別は問題になりません。これは、JMM が「スレッド内 as-if-serial」セマンティクスを使用するためです。したがって、コンストラクター内でのフィールドの割り当ては、フィールドが読み取られる前に常に行われます。

フィールドが の場合final、JMM は、参照がどのように公開されても、呼び出し元が正しい値を表示することを保証します。したがってfinal、同期の形式を使用せずにインスタンスを他のスレッドに渡したい場合に役立ちます。

于 2011-10-01T09:51:33.670 に答える
2

現在の形式では、はい、このクラスは不変です。もちろん反射を無視します。

ただし、@ Bozhoが言うように、それを変更するには誰かがメソッドを追加するだけです。

xをfinalにすると、安全性が高まり、意図が明確になります。

于 2011-09-29T13:49:23.023 に答える
2

setAccessibleを使用して、いつでもプライベートフィールドを設定できます。これが、Spring、Hibernate、およびその他のそのようなフレームワークの動作方法です。Aをサブクラス化することも可能である場合、これはAのすべてのインスタンスが不変であるかどうかについての疑問を提起します。

不変性を明示的にすることの主な利点は、コーダーの意図が明確になることです。ファイナルのセッターは存在できないため、コードを読んでいる人がそれを探す必要はありません。私は通常、クラスのコメントで不変性の意図も述べています。

(メカニズムについて質問したので、一般的に不変性の利点を知っていると思います。)

于 2011-09-29T13:49:59.747 に答える
2

それを行うこともできますが、最終的な宣言を行うときにコンパイラが役立ちます。メンバー変数に新しい値を割り当てようとすると、コンパイラーはエラーをスローします。

于 2011-09-29T13:47:50.413 に答える
0

非最終フィールドの値を変更するコードを追加する可能性とは別に、JVM は最終フィールドと非最終フィールドを異なる方法で扱います。Java メモリー・モデルには、このテーマに関するセクションがあります (まったくカジュアルな読み方ではありません)。

于 2011-09-29T13:54:14.450 に答える