最终字段的setter方法

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

inouterr被宣布为final,但他们有各自的(公共)setter方法,这些方法反过来调用他们各自的本地couter-part。

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

一旦我们在Java代码中初始化了最终变量,我们就可以设置它们。

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

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

本机代码可以破坏final的规则。 它还可以打破访问规则和基本类型安全性以及其他各种事物。

关于final字段实际上不是不可变的这一点实际上是在JLS中识别的:参见JLS 17.5.3 。 这样做的要点是,如果你确实改变了final (例如通过反思),某些保证不再成立。 并且更改表示编译时间常量的final的值可能完全没有效果。

但正如@ignis指出的那样, System.in/out/err out/err在JLS中被特别提及为“写保护”( JLS 17.5.4 )而不是正常的final语义。 基本上,这意味着即使变量发生变化, final保证也会保持不变。


为什么变量最终会有一个setter?

在这种特殊情况下,1)防止System.in/out/err被意外分配破坏,2)以便SecurityManager可以控制更改。

final使Java Compiler确保没有代码尝试更改除初始化之外的字段。 在java.lang.System中它是不同的

public static void setOut(PrintStream out) { checkIO(); setOut0(out); }

private static native void setOut0(PrintStream out);

从javac的角度来看,没有违规行为。

在源代码中,它们不会在setOut()方法中重新分配例如out变量

 public static void setOut(PrintStream out) { checkIO(); setOut0(out); } 

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