2015-02-08 77 views
1

我知道,在java中,抽象類只能被引用,但不能被初始化。 InputStream是一個抽象類,並在System類我注意到下面的聲明,如何初始化InputStream類型的System.in?

static InputStream in; 

因此,如果我們想要的代碼System.in.read()工作,可變in需要進行初始化。

我的問題是java如何做到這一點?如果InputStream是抽象的,其他一些子類應該擴展它。默認哪個類是?

+1

它可能會出現在你沒有源代碼的地方 - 無論是在內部類中(Sun.package中的某個地方)還是JVM本身。 – immibis 2015-02-08 04:01:51

回答

4

幸運的是,它很容易檢查對象System.in的類型是指:

System.out.println(System.in.getClass().getName()); 

版畫(對我來說):

java.io.BufferedInputStream 

所以這是一個BufferedInputStream 。它是什麼包裝?那麼,

Field f = FilterInputStream.class.getDeclaredField("in"); 
f.setAccessible(true); 
Syystem.out.println(f.get(System.in).getClass().getName()); 

打印(再次,對我來說):

java.io.FileInputStream 

所以System.inFileInputStream包裹在BufferedInputStream。這很有意義,如果你認爲大多數操作系統都像文件一樣對待控制檯。實際上,這個FileInputStreamFileDescriptor.in所指的「文件」中讀取。

通過搜索引用FileDescriptor.in,我發現那裏System.in被初始化代碼:私人靜態方法System.initializeSystemClass

FileInputStream fdIn = new FileInputStream(FileDescriptor.in); 
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out); 
FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err); 
setIn0(new BufferedInputStream(fdIn)); 
setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding"))); 
setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding"))); 

initializeSystemClass可能是由本地代碼調用,因爲似乎沒有引用它。

+0

你有我的感激之情。 – 2015-02-08 04:23:29

+0

它在'(hotspot)src/share/vm/runtime/thread.cpp'的'JvmtiExport :: post_vm_start'中被調用。 – Yuning 2016-10-26 17:26:52

-1

System類的聲明如下:

public final static InputStream in = null; 

請大家看看javadocs

「標準」 輸入流。這個流已經打開並準備好供應輸入數據 。通常,此流對應於鍵盤輸入 或主機環境或用戶指定的另一個輸入源。

這意味着當JVM啓動時,System.in由Java運行時初始化。關於你的問題:

如果InputStream是抽象的,其他一些子類應該擴展它。 默認那個類是?

很多類擴展InputStream類,如:FileInputStreamObjectInputStream,...

3

在JVM引導過程中發生的一些黑魔法會將in初始化爲正確的值。

例如,在Java 8中,它是通過名爲initializeSystemClass()的私有方法完成的。 javadoc評論說:

「初始化系統類,線程初始化後調用。」

閱讀source code瞭解血淋淋的細節。他們可以改變從一個Java版本到下一個...雖然沒出現的Java 6和Java 8

Notes之間發生了變化:

  1. System.in,out,err實際的設定由完成native方法。這些本地方法也被System.set{In,Out,Err}方法使用。

  2. 在Java 6到Java 8中,in字段被初始化爲包含FileInputStreamBufferedInputStream。有趣的是,輸入流通常不適用於文件系統中的對象。