使用反射以及http://docs.oracle.com所提供的安装程序中已安装的JDK中提供的src.zip,我找到了java.lang.System
的以下字段,
, out & 错误被宣布为最终版,但他们有各自的(公共)setter方法,这些方法又会调用各自的本地部分。
例如,我可以成功地将控制台输出重定向到文件。
我们可以在Java代码中初始化后设置最终变量。
我的问题是:这个最终规则不适用于本机代码吗?
答案 0 :(得分:12)
我的问题是:这个最终规则不适用于本机代码吗?
原生代码可能会破坏final
上的规则。它还可以打破访问规则和基本类型安全以及其他各种因素。
关于final
字段实际上不是不可变的点实际上在JLS中被识别:请参阅JLS 17.5.3。其中的要点是,如果您确实更改了final
(例如通过反射),则某些保证不再保留。并且更改代表编译时常量的final
的值可能完全没有效果。
但正如@ignis指出的那样,System.in/out/err
在JLS中被特别提及为“写保护”(JLS 17.5.4)而不是正常的final
语义。基本上,这意味着即使变量发生变化,final
也会保证执行。
为什么变量在最终会有一个setter时才是最终的?
在这种特殊情况下,1)防止System.in/out/err
被意外分配所破坏,2)以便SecurityManager
可以控制变化。
答案 1 :(得分:2)
final
使Java编译器确保没有代码尝试更改除初始化之外的字段。在java.lang.System中它是不同的
public static void setOut(PrintStream out) {
checkIO();
setOut0(out);
}
private static native void setOut0(PrintStream out);
从javac的角度来看,没有违规行为。
答案 2 :(得分:1)
在源代码中,它们不会重新分配out
方法中的setOut()
变量
public static void setOut(PrintStream out) {
checkIO();
setOut0(out);
}
他们将传递的流发送到本机代码,并且该代码负责将该流设置为当前使用。因此,最终变量不会被重置,并且此变量不会在本机代码中使用,无论它传递给本机代码的流是什么,它都使用