2015-02-08 89 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。有趣的是,输入流通常不适用于文件系统中的对象。