0
import java.io.*;

class SetOutExample
{
    public static void main(String...s)throws IOException
    {
        FileOutputStream fout=new FileOutputStream("abc123.txt");
        PrintStream ps=new PrintStream(fout);
        System.out.println("hello");
        System.setOut(ps);
        System.out.println("hi");
    }
}

Here the output of hi is printed on a file abc123.txt. How does the PrintStream-type variable out which is final and has the reference to print on screen get modified and start pointing to file abc123.txt? How does setOut work.

ApproachingDarknessFish
  • 14,133
  • 7
  • 40
  • 79
Sourabh.
  • 13
  • 2

2 Answers2

2

Take a look on source code of java.lang.System:

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

The job is done by setOut0(out):

private static native void setOut0(PrintStream out);

This method is native. It can do whatever it wants including changing of value of final fields.

BTW theoretically it can be done using pure java as well. They could use wrapper PrintStream to initialize System.out. In this case setOut() could go to the wrapper and change object that it wraps.

AlexR
  • 114,158
  • 16
  • 130
  • 208
2

OK, notwithstanding the confusing English, it appears that the problem here is "how come System.out, which is supposedly final as per the Java sources, can be modified via .setOut()".

Well, "all bets are out" here; If you look at the System's .set{Out,In,Err}() methods, at least in Oracle's JDK, you will see that ultimately they call these methods:

// emphases mine
private static **native** void setIn0(InputStream in);
private static **native** void setOut0(PrintStream out);
private static **native** void setErr0(PrintStream err);

Native code will do "whatever it wants" in order to achieve its goals; it won't care about such a "petty" thing that is "final" in the Java language. In this case, these methods have the special privilege of modifying std{in,out,err} under the scene without even the process running the JVM noticing.

Short story: magic. Long story: well, those methods work so just use them, and don't heed the final; it is only there so that your code cannot reassign System.{out,in,err} and you have to go through the dedicated methods instead.


Mind you, any calls to .set{In,Out,Err}() will first entail a check against the current security manager, if any; this means you can prevent these methods from acting at all if the need arises.

fge
  • 119,121
  • 33
  • 254
  • 329