Question

When looking into the implementation of the java.lang.System class, I find this:

public final static PrintStream out = null;

From that definition alone, I can tell that the value of System.out will always be null. However, it is initialized when the program starts (with the System.initializeSystemClass() method auto-invoked by the JVM), and I can change its value using System.setOut, which performs a security check, then delegates the call to the setOut0 method which is a native method that changes the value of System.out. Why is it that I can change the value of System.out even though it is declared final?

Was it helpful?

Solution 2

I'm asking how can the value of a final field can be changed by native code.

It works the same way any other bit of native code changes a fields value. Modifications to a final variable are detected at compile time, by the compiler. There are no runtime checks for it aside from explicit checks initiated by a call to Field.set(). At no point is any runtime memory protection or anything else involved, and even if it was, it would be done by the JVM, not the operating system. Native code doesn't have to care about meta data on fields, it can just set bytes in memory. It's fully outside the scope of the Java compiler's compile time checks.

Native code modifications to final fields may not even be visible throughout the entire program because of optimizations the compiler is allowed to perform on final fields. That's what that nullPrintStream() bit was about pre Java 7.

OTHER TIPS

This is a historical wart in the API. The JLS actually special-cases System.{in,out,err}, and if the API were being designed today, there would probably be a different declaration.

This odd behavior is implemented in practice by ignoring the Java definition of System. System is one of the core classes (along with Runtime, Object, the system ClassLoader, and a few others) that are a Java program's interface to the environment outside the JVM. In order to perform their tasks, they have to be supplied in (mostly) native code by the JRE, and in this case the actual C code for System just ignores the fact that the Java API declares the field final.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top