Java 如何初始化InputStream类型的System.in?

Java 如何初始化InputStream类型的System.in?,java,Java,我知道,在java中,抽象类只能被引用,不能被初始化InputStream是一个抽象类,在系统类中,我注意到以下声明 static InputStream in; 因此,如果我们希望代码System.in.read()工作,则需要初始化变量in 我的问题是java是如何做到这一点的?如果InputStream是抽象的,那么其他一些子类应该扩展它。默认情况下是哪个类?系统类中的声明如下: public final static InputStream in = null; 请看一下: “标准”

我知道,在java中,抽象类只能被引用,不能被初始化
InputStream
是一个抽象类,在
系统
类中,我注意到以下声明

static InputStream in;
因此,如果我们希望代码
System.in.read()
工作,则需要初始化变量
in


我的问题是java是如何做到这一点的?如果
InputStream
是抽象的,那么其他一些子类应该扩展它。默认情况下是哪个类?

系统类中的声明如下:

public final static InputStream in = null;
请看一下:

“标准”输入流。此流已打开并准备就绪 提供输入数据。通常,该流对应于键盘输入 或主机环境或用户指定的其他输入源

这意味着当JVM启动时,System.in由Java运行时初始化。关于你的问题:

如果InputStream是抽象的,那么其他一些子类应该对其进行扩展。 默认情况下是哪个类


许多类扩展了
InputStream
类,如:,…

系统
类中的声明如下:

public final static InputStream in = null;
请看一下:

“标准”输入流。此流已打开并准备就绪 提供输入数据。通常,该流对应于键盘输入 或主机环境或用户指定的其他输入源

这意味着当JVM启动时,System.in由Java运行时初始化。关于你的问题:

如果InputStream是抽象的,那么其他一些子类应该对其进行扩展。 默认情况下是哪个类


许多类扩展了
InputStream
类,如:,…

幸运的是,检查对象的类型
系统很容易。in
指:

System.out.println(System.in.getClass().getName());
印刷品(为我):

所以它是一个
缓冲输入流
。它是什么?那么

Field field = FilterInputStream.class.getDeclaredField("in");
field.setAccessible(true);   
System.out.println(field.get(System.in).getClass().getName());
印刷品(对我来说也是):

因此,
System.in
是一个
FileInputStream
包装在
BufferedInputStream
中。这是有意义的,如果您认为大多数操作系统都以与文件相同的方式处理控制台。实际上,这个
FileInputStream
从引用的“文件”中读取

通过搜索对
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
可能由本机代码调用,因为似乎没有对它的引用。

幸运的是,检查对象的类型
系统很容易。in
指:

System.out.println(System.in.getClass().getName());
印刷品(为我):

所以它是一个
缓冲输入流
。它是什么?那么

Field field = FilterInputStream.class.getDeclaredField("in");
field.setAccessible(true);   
System.out.println(field.get(System.in).getClass().getName());
印刷品(对我来说也是):

因此,
System.in
是一个
FileInputStream
包装在
BufferedInputStream
中。这是有意义的,如果您认为大多数操作系统都以与文件相同的方式处理控制台。实际上,这个
FileInputStream
从引用的“文件”中读取

通过搜索对
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
可能由本机代码调用,因为似乎没有对它的引用。

在JVM引导过程中,幕后会发生一些黑魔法,将
中的
初始化为正确的值

例如,在Java8中,它是由一个名为
initializeSystemClass()
的私有方法完成的。javadoc评论说:

“初始化系统类。在线程初始化后调用。”

阅读这篇文章,了解血淋淋的细节。它们可能在不同的Java版本中有所不同。。。尽管它们在Java6和Java8之间似乎没有改变

注:

  • System.in、out、err
    的实际设置是通过
    native
    方法完成的。
    System.set{In,Out,Err}
    方法也使用这些本机方法

  • 在Java 6到Java 8中,
  • 中的
    字段被初始化为一个
    BufferedInputStream
    ,它封装了一个
    FileInputStream
    。有趣的是,输入流通常不是针对“文件”。。。在/a文件系统中的对象意义上


    在JVM引导过程中,有一些黑魔法在幕后发生,将
    中的
    初始化为正确的值

    例如,在Java8中,它是由一个名为
    initializeSystemClass()
    的私有方法完成的。javadoc评论说:

    “初始化系统类。在线程初始化后调用。”

    阅读这篇文章,了解血淋淋的细节。它们可能在不同的Java版本中有所不同。。。尽管它们在Java6和Java8之间似乎没有改变

    注:

  • System.in、out、err
    的实际设置是通过
    native
    方法完成的。
    System.set{In,Out,Err}
    方法也使用这些本机方法

  • 在Java 6到Java 8中,
  • 中的
    字段被初始化为一个
    BufferedInputStream
    ,它封装了一个
    FileInputStream
    。有趣的是,输入流通常不是针对“文件”。。。在/a文件系统中的对象意义上


    它很可能位于一个您没有源代码的地方-在一个内部类(sun.package中的某个地方)或JVM本身中。它很可能位于一个您没有源代码的地方-在一个内部类(sun.package中的某个地方)或者在JVM内部。我感谢你。它在
    JvmtiExport::post_vm_start
    中调用,在
    (热点)src/share/vm/runtime/thread.cpp中调用。我感谢你。它在
    JvmtiExport::post_vm_start
    中调用