我知道,在java中,抽象类只能被引用,但不能被初始化。 InputStream
是一个抽象类,并在System
类我注意到下面的声明,如何初始化InputStream类型的System.in?
static InputStream in;
因此,如果我们想要的代码System.in.read()
工作,可变in
需要进行初始化。
我的问题是java如何做到这一点?如果InputStream
是抽象的,其他一些子类应该扩展它。默认哪个类是?
我知道,在java中,抽象类只能被引用,但不能被初始化。 InputStream
是一个抽象类,并在System
类我注意到下面的声明,如何初始化InputStream类型的System.in?
static InputStream in;
因此,如果我们想要的代码System.in.read()
工作,可变in
需要进行初始化。
我的问题是java如何做到这一点?如果InputStream
是抽象的,其他一些子类应该扩展它。默认哪个类是?
幸运的是,它很容易检查对象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.in
是FileInputStream
包裹在BufferedInputStream
。这很有意义,如果你认为大多数操作系统都像文件一样对待控制台。实际上,这个FileInputStream
从FileDescriptor.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
可能是由本地代码调用,因为似乎没有引用它。
你有我的感激之情。 – 2015-02-08 04:23:29
它在'(hotspot)src/share/vm/runtime/thread.cpp'的'JvmtiExport :: post_vm_start'中被调用。 – Yuning 2016-10-26 17:26:52
在System
类的声明如下:
public final static InputStream in = null;
请大家看看javadocs:
“标准” 输入流。这个流已经打开并准备好供应输入数据 。通常,此流对应于键盘输入 或主机环境或用户指定的另一个输入源。
这意味着当JVM启动时,System.in由Java运行时初始化。关于你的问题:
如果InputStream是抽象的,其他一些子类应该扩展它。 默认那个类是?
很多类扩展InputStream
类,如:FileInputStream,ObjectInputStream,...
在JVM引导过程中发生的一些黑魔法会将in
初始化为正确的值。
例如,在Java 8中,它是通过名为initializeSystemClass()
的私有方法完成的。 javadoc评论说:
“初始化系统类,线程初始化后调用。”
阅读source code了解血淋淋的细节。他们可以改变从一个Java版本到下一个...虽然没出现的Java 6和Java 8
Notes之间发生了变化:
的System.in,out,err
实际的设定由完成native
方法。这些本地方法也被System.set{In,Out,Err}
方法使用。
在Java 6到Java 8中,in
字段被初始化为包含FileInputStream
的BufferedInputStream
。有趣的是,输入流通常不适用于文件系统中的对象。
它可能会出现在你没有源代码的地方 - 无论是在内部类中(Sun.package中的某个地方)还是JVM本身。 – immibis 2015-02-08 04:01:51