web-dev-qa-db-ja.com

Java最終修飾子

finalの影響を誤解していると言われました。 finalキーワードの効果は何ですか?

ここに私が思うことの簡単な概要があります、私は知っています:

Java最終修飾子(別名集約関係)

プリミティブ変数:1回のみ設定できます。 (メモリとパフォーマンスの向上)
オブジェクト変数:変更可能、最終はオブジェクト参照に適用されます。
フィールド:1回のみ設定できます。
メソッド:オーバーライド、非表示はできません。
クラス:拡張できません。
ガベージコレクション:Java世代別ガベージコレクションのマークスイープからダブルスイープへの強制).

缶とカント

  • クローンが失敗する可能性があります(これは良いことでも悪いことでもあります)
  • 不変のプリミティブ(別名const)を作成できます
  • 空白を不変にすることができます-作成時に初期化、別名読み取り専用
  • オブジェクトを浅く不変にすることができます
  • スコープ/可視性を不変にすることができます
  • メソッド呼び出しのオーバーヘッドを小さくすることができます(仮想テーブルを必要としないため)
  • メソッドの引数をfinalとして使用できます(thyがそうでない場合でも)
  • オブジェクトをスレッドセーフにすることができます(オブジェクトがfinalとして定義されている場合、メソッドの引数をfinalにすることはできません)
  • 模擬テストを行うことができます(それについて何もできません-バグが意図されていると言うことができます)
  • 友達を作ることはできません(他の友達とは不変で、残りは不変です)
  • 後で不変になるように変更されたミュータブルを作成することはできません(ただし、修正のようなファクトリーパターンでは可能です)
  • 配列要素を不変(別名不変)にすることはできません
  • オブジェクトの新しいインスタンスを作成できません(これは良い点と悪い点の両方です)
  • シリアル化が機能しない

finalに代わるものはありませんが、ラッパー+プライベートおよび列挙があります。

54
Margus

各ポイントに順番に答えます。

プリミティブ変数:1回のみ設定できます。 (メモリとパフォーマンスの向上)

はい。ただし、メモリゲインもパフォーマンスゲインもありません。 (想定されるパフォーマンスの向上は、finalからではなく、一度だけ設定することから得られます。)

オブジェクト変数:変更可能、最終はオブジェクト参照に適用されます。

はい。 (ただし、この説明では、残りのJava言語がオブジェクト/参照の二重性を処理する方法と完全に一致しているという点を見逃しています。たとえば、オブジェクトがパラメーターとして渡され、結果として返される場合)

フィールド:1回のみ設定できます。

実際の答えは、変数の場合と同じです。

メソッド:オーバーライド、非表示はできません。

はい。ただし、ここで行われていることは、フィールド/変数のfinalとは異なる何かを意味するために、finalキーワードが異なる構文コンテキストで使用されていることにも注意してください。

クラス:拡張できません。

はい。ただし、上記の注も参照してください。

ガベージコレクション:Java世代のガベージコレクションマークスイープを強制的にダブルスイープします。

これはナンセンスです。 finalキーワードには、ガベージコレクションとの関連性はありませんwhatevereverfinalとファイナライズを混同している可能性があります...それらは無関係です。

しかし、ファイナライザーでさえ余分なスイープを強制しません。何が起こるかというと、メインGCが終了するまで、ファイナライズを必要とするオブジェクトが一方に設定されます。次に、GCはオブジェクトに対してfinalizeメソッドを実行し、そのフラグを設定して...続行します。次回GCを実行すると、オブジェクトは通常のオブジェクトとして扱われます。

  • それが到達可能である場合、マークされ、コピーされます
  • 到達可能でない場合はマークされません。

(あなたの特性-「Java世代別ガベージコレクションのマークスイープ」は文字化けしています。ガベージコレクタは、「マークスイープ」OR「世代別」(「コピー」のサブクラス)のいずれかです。 Javaは通常世代別コレクションを使用し、緊急時にマークスイープにフォールバックします。つまり、スペースが不足したとき、またはローポーズコレクタが追いつかないときです。)

クローンが失敗する可能性があります(これは良いことでも悪いことでもあります)

そうは思いません。

不変のプリミティブ(別名const)を作成できます

はい。

空白を不変にすることができます-作成時に初期化、別名読み取り専用

はい...以前に使用された「ブランク不変」という用語を聞いたことがありませんが。

オブジェクトを浅く不変にすることができます

オブジェクトの可変性とは、観測可能な状態が変化するかどうかです。そのため、属性finalを宣言すると、オブジェクトが不変として動作する場合としない場合があります。さらに、「浅い」という概念は明確に定義されていません。特に、「浅い」という概念は、クラスセマンティクスの深い知識なしではマッピングできないためです。

(明確にするために、変数/フィールドの可変性は、JLSのコンテキストで明確に定義された概念です。JLSの観点から定義されていないのは、オブジェクトの可変性の概念だけです。)

スコープ/可視性を不変にすることができます

用語エラー。可変性はオブジェクトの状態に関するものです。可視性と範囲はそうではありません。

メソッド呼び出しのオーバーヘッドを小さくすることができます(仮想テーブルを必要としないため)

実際には、これは無関係です。最新のJITコンパイラーは、アプリケーションが実際に使用するクラスによってオーバーライドされない場合、非最終メソッドに対してもこの最適化を行います。 (巧妙なことが起こる...)

メソッドの引数をfinalとして使用できます(thyがそうでない場合でも)

え?この文を解析できません。

オブジェクトをスレッドセーフにすることができます

特定の状況では、はい。

(オブジェクトがfinalとして定義されている場合、メソッドの引数をfinalにすることはありません)

はい、classが最終的な場合を意味します。オブジェクトは最終的なものではありません。

模擬テストを行うことができます(それについて何もできません-バグが意図されていると言うことができます)

解析しません。

友達を作ることはできません(他の友達とは不変で、残りは不変です)

Javaには「友人」がいません。

後で不変になるように変更されたミュータブルを作成することはできません(ただし、修正のようなファクトリーパターンでは可能です)

最初のはい、finalフィールドは可変から不変に切り替えることはできません。

2番目の部分の意味が明確ではありません。ファクトリ(またはビルダー)パターンを使用して不変オブジェクトを構築できることは事実です。ただし、オブジェクトフィールドにfinalを使用すると、どの時点でもオブジェクトは変更できません。

または、非最終フィールドを使用して不変状態を表す不変オブジェクトを実装し、APIを設計して、「スイッチを切り替え」て、以前から変更可能なオブジェクトを不変にすることができます。ただし、このアプローチを採用する場合、オブジェクトをスレッドセーフにする必要がある場合は、同期をより慎重に行う必要があります。

配列要素を不変(別名不変)にすることはできません

はい。ただし、用語は壊れています。 「浅い可変性」に関する上記のコメントを参照してください。

オブジェクトの新しいインスタンスを作成できません(これは良い点と悪い点の両方です)

いいえ。最終フィールド、最終クラス、または最終メソッドを持つオブジェクトの新しいインスタンスを作成するのを妨げるものは何もありません。

シリアル化が機能しない

いいえ。シリアル化は機能します。 (カスタムfinalメソッドを使用したreadObjectフィールドの逆シリアル化には問題がありますが、リフレクションハックを使用して回避できます。)

Finalに代わるものはありませんが、

正しい。

しかし、ラッパー+プライベートがあります

はい、厳密に言えば、非最終フィールドの非同期ゲッターはスレッドセーフではない可能性があります... オブジェクト構築中に初期化され、その後変更されない場合でも

および列挙型。

別の問題を解決します。また、enumsは変更可能です。

74
Stephen C

通常、最終キーワードは不変性を保持するために使用されます。クラスまたはメソッドにfinalを使用することは、メソッド間のリンクが壊れないようにすることです。たとえば、クラスXのメソッドの実装で、メソッドMが特定の方法で動作することを前提としているとします。 XまたはMをfinalとして宣言すると、Xが正しく動作しないように、派生クラスがMを再定義することを防ぎます。

2
Katie