1

在查看java.lang.System类的实现时,我发现:

public final static PrintStream out = null;

仅从该定义中,我就可以看出 的值System.out将始终为null。但是,它在程序启动时被初始化(使用System.initializeSystemClass()JVM 自动调用的方法),我可以使用 更改其值System.setOut,执行安全检查,然后将调用委托给setOut0方法,该native方法是更改​​值的方法的System.out。为什么System.out即使它被声明我也可以改变它的值final

4

2 回答 2

6

这是 API 中的一个历史缺陷。JLS 实际上是特殊情况System.{in,out,err},如果现在设计 API,可能会有不同的声明。

这种奇怪的行为实际上是通过忽略 Java 的定义来实现的SystemSystem是核心类之一(与RuntimeObject、 systemClassLoader和其他一些类一起),它们是 Java 程序与 JVM 外部环境的接口。为了执行它们的任务,它们必须(大部分)由 JRE 以本机代码提供,在这种情况下,实际的 C 代码System只是忽略了 Java API 声明字段的事实final

于 2013-08-14T21:54:55.387 回答
1

我在问如何通过本机代码更改最终字段的值。

它的工作方式与任何其他本地代码更改字段值的方式相同。final编译器在编译时检测到对变量的修改。除了调用Field.set(). 在任何时候都没有任何运行时内存保护或任何其他涉及,即使是这样,它也将由 JVM 完成,而不是操作系统。本机代码不必关心字段上的元数据,它可以只在内存中设置字节。它完全超出了 Java 编译器的编译时检查范围。

由于允许编译器对字段执行优化,对字段的本机代码修改final甚至可能在整个程序中都不可见final。这就是nullPrintStream()Java 7 之前的内容。

于 2013-08-15T00:47:11.033 回答