How “System.out.println” works internally in Java?

Let’s discuss “How System.out.println works internally in Java“:

This is one of the frequently asked question in Java interview at freshers level as well as experienced level, so today I will try to explain the inside code of this statement.
System.out.println” is simply defined as : calling println() method of PrintStream class whose object out is initialized in System class.

Lets first understand what System.out is and what exactly it do.

There is a class in which System.out is declared, where out is the object of PrintStream class:

public final static PrintStream out = nullPrintStream();

Below is the code for nullPrintStream():

private static PrintStream nullPrintStream() throws NullPointerException {
    if (currentTimeMillis() > 0) {
        return null;
    throw new NullPointerException();


So as shown is above code nullPrintStream() simply returning null or throws an exception, but actually it does not.
Here is the explanation:

When System class get initialized, it calls initializeSystemClass() method:

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
In this code setOut0() is a native function implemented in System.c:

Java_java_lang_System_setOut0(JNIEnv *env, jclass cla, jobject stream)
    jfieldID fid =
    if (fid == 0)

This is a standard JNI code that sets System.out to the argument passed to it, this method calls the native method setOut0() which sets the out variable to the appropriate value.

System.out is final, it means it cannot be set to something else in initializeSystemClass() but using native code it is possible to modify a final variable.

Now lets discuss what is a FileDescriptor?

As you already see below line of code:

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
A FileOutputStream object is created using input value as FileDescriptor.out.

The FileDescriptor class not belongs to directory because FileDescriptor is much lower level than most of the Java standard library. While most .java files are platform independent, there are actually different implementations of FileDescriptor for different platforms.

A FileDescriptor object holds is an integer. The constructor of FileDescriptor takes an integer and creates a FileDescriptor containing that integer. and which is used to initialize a FileOutputStream object.

Here is the code of FileDescriptor.out:

public static final FileDescriptor out = new FileDescriptor(1);


Now let’s discuss how println() is defined in class which is a higher level class, it used to write different kinds of data, flushing and handling errors.

public void println(String x) {
    synchronized (this) {
Following the call stack to print():

public void print(String s) {
    if (s == null) {
        s = "null";
Going deeper, and look at write() method:

private void write(String s) {
    try {
        synchronized (this) {
        if (autoFlush && (s.indexOf('\n') >= 0))
    catch (InterruptedIOException x) {
    catch (IOException x) {
        trouble = true;

Internally, the PrintStream object (System.out) contains three different objects:
charOut – The OutputStreamWriter object used to write character arrays into a stream.
textOut – The BufferedWriter object used to write character arrays as well as strings and text array.
out – A BufferedOutputStream object passed all the way down the call stack and used much lower than at the PrintStream level.

Here PrintStream.write() calls BufferedWriter.write() which is actually defined in the abstract class

public void write(String str) throws IOException {
    write(str, 0, str.length());

public void write(String s, int off, int len) throws IOException {
    synchronized (lock) {

        int b = off, t = off + len;
        while (b < t) {
            int d = min(nChars - nextChar, t - b);
            s.getChars(b, b + d, cb, nextChar);
            b += d;
            nextChar += d;
            if (nextChar >= nChars)
Data is stored in a data buffer until it’s written all at once, or flushed. Buffered IO is much faster than simply writing to the hardware one byte at a time.

Java Professional with rich experience in Java development.
– Designing and developing high-volume, low-latency applications with high-availability and performance.
– Writing well designed, robust and efficient code.

Have any Question or Comment?

Leave a Reply

Your email address will not be published. Required fields are marked *

LinkedIn Auto Publish Powered By :