java: "final" System.out, System.in and System.err?
final, java
Solution
JLS 17.5.4 Write Protected Fields:
Normally, final static fields may not be modified. However `System.in`, `System.out`, and `System.err` are final static fields that, for legacy reasons, must be allowed to be changed by the methods `System.setIn`, `System.setOut` and `System.setErr`. We refer to these fields as being write-protected to distinguish them from ordinary final fields.
The compiler needs to treat these fields differently from other final fields. For example, a read of an ordinary final field is "immune" to synchronization: the barrier involved in a lock or volatile read does not have to affect what value is read from a final field. Since the value of write-protected fields may be seen to change, synchronization events should have an effect on them. Therefore, the semantics dictate that these fields be treated as normal fields that cannot be changed by user code, unless that user code is in the `System` class.
By the way, actually you can mutate `final` fields via reflection by calling `setAccessible(true)` on them (or by using `Unsafe` methods). Such techniques are used during deserialization, by Hibernate and other frameworks, etc, but they have one limitation: code that have seen value of final field before modification is not guaranteed to see the new value after modification. What's special about the fields in question is that they are free of this limitation since they are treated in special way by the compiler.
Problem
`System.out` is declared as `public static final PrintStream out`. But you can call `System.setOut()` to reassign it. Huh? How is this possible if it's `final`? (same point applies to `System.in` and `System.err`) And more importantly, if you can mutate the public static final fields, what does this mean as far as the guarantees (if any) that `final` gives you? (I never realized nor expected System.in/out/err behaved as `final` variables)