本帖最后由 FFleo 于 2015-3-11 22:31 编辑
in 是java.lang.System的一个静态成员(static),这里的in是一个InputStream子实现类的实体,因此in拥有InputStream的方法。
同理System.out 和 System.err,JVM启动的时候通过Java运行时初始化这3个流,所以你不需要初始化它们。
查看System.in的声明:
- public final class System {
- .....
- /**
- * The "standard" input stream. This stream is already
- * open and ready to supply input data. Typically this stream
- * corresponds to keyboard input or another input source specified by
- * the host environment or user.
- */
- public final static InputStream in = null;
- .....
- /**
- * Reassigns the "standard" input stream.
- *
- * <p>First, if there is a security manager, its <code>checkPermission</code>
- * method is called with a <code>RuntimePermission("setIO")</code> permission
- * to see if it's ok to reassign the "standard" input stream.
- * <p>
- *
- * @param in the new standard input stream.
- *
- * @throws SecurityException
- * if a security manager exists and its
- * <code>checkPermission</code> method doesn't allow
- * reassigning of the standard input stream.
- *
- * @see SecurityManager#checkPermission
- * @see java.lang.RuntimePermission
- *
- * @since JDK1.1
- */
- public static void setIn(InputStream in) {
- checkIO();
- setIn0(in);
- }
- //......
- }
复制代码
System.in 在JDK1.0的时候其实不是final的,通过对覆盖in来达到输入重定向,从JDK1.1开始改为final,提供的setIn方法来重定向输入流。
如果setIn是重定向System.in,并非对System.in初始化,那么问题来了
——System.in是如何初始化的?
实际上System.in是在JVM启动时,通过native方法初始化的。在java.lang.System开头其实有这么一段代码:
- public final class System {
- /* register the natives via the static initializer.
- *
- * VM will invoke the initializeSystemClass method to complete
- * the initialization for this class separated from clinit.
- * Note that to use properties set by the VM, see the constraints
- * described in the initializeSystemClass method.
- */
- private static native void registerNatives();
- static {
- registerNatives();
- }
- //......
- }
复制代码
这里的注释说明了VM会通过调用initializeSystemClass方法来完成类的初始化。我们再看看这个方法:
- /**
- * Initialize the system class. Called after thread initialization.
- */
- private static void initializeSystemClass() {
- // VM might invoke JNU_NewStringPlatform() to set those encoding
- // sensitive properties (user.home, user.name, boot.class.path, etc.)
- // during "props" initialization, in which it may need access, via
- // System.getProperty(), to the related system encoding property that
- // have been initialized (put into "props") at early stage of the
- // initialization. So make sure the "props" is available at the
- // very beginning of the initialization and all system properties to
- // be put into it directly.
- props = new Properties();
- initProperties(props); // initialized by the VM
- // There are certain system configurations that may be controlled by
- // VM options such as the maximum amount of direct memory and
- // Integer cache size used to support the object identity semantics
- // of autoboxing. Typically, the library will obtain these values
- // from the properties set by the VM. If the properties are for
- // internal implementation use only, these properties should be
- // removed from the system properties.
- //
- // See java.lang.Integer.IntegerCache and the
- // sun.misc.VM.saveAndRemoveProperties method for example.
- //
- // Save a private copy of the system properties object that
- // can only be accessed by the internal implementation. Remove
- // certain system properties that are not intended for public access.
- sun.misc.VM.saveAndRemoveProperties(props);
- lineSeparator = props.getProperty("line.separator");
- sun.misc.Version.init();
- FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
- FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
- FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
- setIn0(new BufferedInputStream(fdIn));
- setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
- setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true));
- // Load the zip library now in order to keep java.util.zip.ZipFile
- // from trying to use itself to load this library later.
- loadLibrary("zip");
- // Setup Java signal handlers for HUP, TERM, and INT (where available).
- Terminator.setup();
- // Initialize any miscellenous operating system settings that need to be
- // set for the class libraries. Currently this is no-op everywhere except
- // for Windows where the process-wide error mode is set before the java.io
- // classes are used.
- sun.misc.VM.initializeOSEnvironment();
- // The main thread is not added to its thread group in the same
- // way as other threads; we must do it ourselves here.
- Thread current = Thread.currentThread();
- current.getThreadGroup().add(current);
- // register shared secrets
- setJavaLangAccess();
- // Subsystems that are invoked during initialization can invoke
- // sun.misc.VM.isBooted() in order to avoid doing things that should
- // wait until the application class loader has been set up.
- // IMPORTANT: Ensure that this remains the last initialization action!
- sun.misc.VM.booted();
- }
复制代码
JVM会判断当前操作系统,并决定对应的初始化方法。同一JVM命令和不同OS的API的对照关系是不同的。
总结一下:
in的初始化是由JVM启动时完成的,根据当前操作系统封装了对应OS的标准输入的系统调用。
in的具体实现类也是Native的,而in.read(),其实是JVM调用了OS提供的获取键盘输入的API。 |