java: “最终” System.out、System.in 和 System.err?
System.out
< /a> 被声明为 public static final PrintStream out
。
但是您可以调用 System.setOut()
重新分配它。
啊?如果它是最终
,这怎么可能?
(同样的一点也适用于 System.in
和 System.err
)
更重要的是,如果您可以改变公共静态最终字段,那么就保证而言这意味着什么(如果有的话)final
给了你什么? (我从未意识到也不期望 System.in/out/err 表现为 final
变量)
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
JLS 17.5.4 写保护字段:
顺便说一句,实际上您可以通过反射调用
setAccessible(true)
(或使用Unsafe
方法)来改变final
字段。 Hibernate 和其他框架等在反序列化过程中使用了此类技术,但它们有一个限制:在修改之前已经看到 Final 字段值的代码不能保证在修改后看到新值。这些字段的特殊之处在于它们不受此限制,因为编译器以特殊方式处理它们。JLS 17.5.4 Write Protected Fields:
By the way, actually you can mutate
final
fields via reflection by callingsetAccessible(true)
on them (or by usingUnsafe
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.Java 使用本机方法来实现
setIn()
、setOut()
和setErr()
。在我的 JDK1.6.0_20 上,
setOut()
看起来像这样:您仍然无法“正常”重新分配
final
变量,即使在这种情况下,您也不能直接重新分配字段(即您仍然无法编译“System.out = myOut
”)。本机方法允许执行一些在常规 Java 中无法执行的操作,这解释了为什么本机方法存在限制,例如需要对小程序进行签名才能使用本机库。Java uses a native method to implement
setIn()
,setOut()
andsetErr()
.On my JDK1.6.0_20,
setOut()
looks like this:You still can't "normally" reassign
final
variables, and even in this case, you aren't directly reassigning the field (i.e. you still can't compile "System.out = myOut
"). Native methods allow some things that you simply can't do in regular Java, which explains why there are restrictions with native methods such as the requirement that an applet be signed in order to use native libraries.为了扩展 Adam 所说的内容,这里是 impl:
并且 setOut0 定义为:
To extend on what Adam said, here is the impl:
and setOut0 is defined as:
取决于实施。最后一个可能永远不会改变,但它可能是实际输出流的代理/适配器/装饰器,例如 setOut 可以设置 out 成员实际写入的成员。但实际上它是本地设置的。
Depends on the implementation. The final one may never change but it could be a proxy/adapter/decorator for the actual output stream, setOut could for example set a member that the out member actually writes to. In practice however it is set natively.
在 System 类中声明为 Final 的
out
是类级别变量。其中下面方法中的 out 是局部变量。
我们无法将类级别传递出去,这实际上是该方法的最后一个级别
上述方法的使用方法如下:
现在将数据转移到文件中。
希望这个解释有意义。
因此,本机方法或反射在改变 Final 关键字的用途方面没有任何作用。
the
out
which is declared as final in System class is a class level variable.where as out which is in the below method is a local variable.
we are no where passing the class level out which is actually a final one into this method
usage of the above method is as below:
now the data will be diverted to the file.
hope this explanation makes the sense.
So no role of native methods or reflections here in changing purpose of the final keyword.
至于如何实现,我们可以看一下
java/lang/System.c
的源代码:也就是说,JNI可以“作弊”。 ; )
As far as how, we can take a look at the source code to
java/lang/System.c
:In other words, JNI can "cheat". ; )
我认为
setout0
正在修改本地级别变量out
,它不能修改类级别变量out
。I think
setout0
is modifying local level variableout
, it can't modify class level variableout
.