System.setIn() reassigns final System.in [duplicate]
Possible Duplicate:
java: "final" System.out, System.in and System开发者_如何学Python.err?
It's just occurred to me although I've done it so many times without paying attention: System.setIn()
is reassigning static final System.in
.
Am I missing something? How is it possible to reassign a final field.
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.
EDIT: Worth to mention is that you can "hack" final fields and set its value 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 3 System fields is that they are free of this limitation since they are treated in special way by the compiler.
System.setIn()
and its friends setOut()
and setErr()
all delegate to native methods, where Java access control rules are not enforced.
Whoever did this and wasted a JLS section[1] explaining it, are just being silly.
These fields should simply drop the final
modifier. It doesn't break binary compatibility. [2]
Allowing user to write System.out=x
isn't a problem; after all he can do System.setOut(x)
anyway. Compiler needs a special handling to translate the 1st assignment to the 2nd method call. That is better than the current way, which twists both read and write semantics of System.out
.
If we really don't want to see System.out=x
, make it an exception so compiler won't compile it.
These 2 solutions are simple syntactic stuff; no need to break Java Memory Model for this silly little thing.
[1] http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.5.4
[2] http://java.sun.com/docs/books/jls/third_edition/html/binaryComp.html#13.4.9
精彩评论