1. ホーム
  2. java

java: "final" System.out、System.in、System.err?

2023-08-12 18:40:34

質問

System.out public static final PrintStream out .

しかし、あなたは System.setOut() を使用して再割り当てすることができます。

あれ?これって、もしや final ?

(同じ点が System.inSystem.err )

さらに重要なことは、もしあなたが public static final フィールドを変異させることができるのであれば、これは final があなたに与える保証に関して、これは何を意味するのでしょうか?(私はSystem.in/out/errの振る舞いが final 変数として振る舞います)

どのように解決するのですか?

JLS 17.5.4 ライトプロテクトフィールド :

通常、最終的な静的フィールドは変更することができません。しかし System.in , System.out そして System.err は最終的な静的フィールドで、レガシーな理由により、メソッド System.setIn , System.setOutSystem.setErr . 私たちはこれらのフィールドを ライトプロテクトフィールド と呼び、通常の最終フィールドと区別しています。

コンパイラは、これらのフィールドを他の最終フィールドとは異なる方法で扱う必要があります。例えば、通常の最終フィールドの読み込みは同期化に対して "immune"です。ロックまたは volatile 読み込みに関わるバリアは、最終フィールドから読み込まれる値に影響を与える必要はありません。書き込み禁止フィールドの値は変更される可能性があるため、同期イベントはそれらに影響を与えるはずです。したがって、セマンティクスでは、これらのフィールドはユーザーコードによって変更されない通常のフィールドとして扱われます。 System クラスでない限り、ユーザーコードによって変更されない通常のフィールドとして扱われます。

ところで、実は final を呼び出すことで、リフレクションを通じて setAccessible(true) を呼び出すことで(あるいは Unsafe メソッドを使って)。このようなテクニックはデシリアライズの間、Hibernateや他のフレームワークなどで使用されますが、1つの制限があります:変更前に最終フィールドの値を見ていたコードは、変更後に新しい値を見ることが保証されていません。問題のフィールドについて特別なことは、コンパイラーによって特別な方法で扱われるため、この制限から解放されることです。