初讀java源碼:詳解System.out.print實現原理


我們往往在main中直接調用System.out.print方法來打印,但是其實就這簡單的一步里面有很多的玄機,因為main是static的,所以只能調用static的函數,那么print是static的嗎?我一直有這個疑問,今天專門查閱了下源碼,說下我的理解:(源碼只貼出來部分對理解有用的)

源碼里面:public final class System 直接在lang包里面。所以可以直接不通過包名就直接調用system類。里面還有:

public final static PrintStream out = nullPrintStream();
............
............

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

可以看出out是system的靜態成員,所以可以通過system.out直接訪問到,但是這時候又有問題了,因為 nullPrintStream()這個函數返回值是null的,怎么可以調用printstream的方法呢。看out的注釋:
/**
* The following two methods exist because in, out, and err must be
* initialized to null. The compiler, however, cannot be permitted to
* inline access to them, since they are later set to more sensible values
* by initializeSystemClass().
*/

大概翻譯后知道剛開始的時候確實是都是null的,那么什么時候能把out指向標准輸出的呢?注釋說看initializeSystemClass()這個函數。

/**
* Initialize the system class. Called after thread initialization.
*/
private static void initializeSystemClass() {
props = new Properties();
initProperties(props);
sun.misc.Version.init();

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
.................
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
...............

...............

 

接着找到FileDescriptor這個類中的靜態成員 out:(用自身定義自身)

public static final FileDescriptor out = standardStream(1);

以及standardStream()方法:

private static FileDescriptor standardStream(int fd) {
FileDescriptor desc = new FileDescriptor();
desc.handle = set(fd);
return desc;
}

這時候返回了 handle為1的FileDescriptor; 在傳統的unix的系統中,文件描述符為0,1,2分別表示為標准輸入,標准輸出和錯誤輸出。

最后調用了setout0方法:

private static native void setOut0(PrintStream out);

 

到這里,setout0是native方法,所以再也追蹤不到以后的細節了,而到這時候,out的出路似乎還沒有找到。但是。在system類中有setout方法即:

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

調用了setout0()方法,而我們知道setout方法是重置輸出流的對象的,因此雖然我們看不到setout0的細節,但是因為setout調用了setout0,我們可以大致猜到setout0是通過調用底層的代碼實現對out的流的重定位的,而initializeSystemClass()這個函數也調用了setout0將fd為1的文件封裝成文件流,再封裝成緩沖流,再封裝成打印流,最后通過setout0將out與這個流綁定。這樣一切就都說通了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM