最终字段的setter方法

时间:2012-12-19 10:49:33

标签: java

使用反射以及http://docs.oracle.com所提供的安装程序中已安装的JDK中提供的src.zip,我找到了java.lang.System的以下字段,

out & 错误被宣布为最终版,但他们有各自的(公共)setter方法,这些方法又会调用各自的本地部分。

例如,我可以成功地将控制台输出重定向到文件。

我们可以在Java代码中初始化后设置最终变量。

我的问题是:这个最终规则不适用于本机代码吗?

3 个答案:

答案 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);
}

他们将传递的流发送到本机代码,并且该代码负责将该流设置为当前使用。因此,最终变量不会被重置,并且此变量不会在本机代码中使用,无论它传递给本机代码的流是什么,它都使用