First of all, System.in is an object of type InputStream, which is like this in the source code:
/**
* 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;
It can be seen that System.in belongs to standard input, and data can be entered through the keyboard or other methods. But in the source code, this object does not have an (explicit) initialization method. By reading the source code, you can find the following method:
/**
* 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);
}
private static native void setIn0(InputStream in);
Reading the comments shows that this method is used to set Studying setIn0(in), it can be seen that this method achieves the setting of in by calling the underlying interface. So how is it initialized when the software is running? There is the following code in the System class:
/* 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();
}
/**
* Initialize the system class. Called after thread initialization.
*/
private static void initializeSystemClass() {
...
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));
...
}
It can be seen from this code that when the software is running, it first runs the static code block and calls the registerNatives() underlying method to initialize the System class. This method calls the initializeSystemClass() method to initialize the System class. These two steps are Implemented through VM, and then read the initializeSystemClass() method, you can see that three pieces of code are called setIn0, setOut0, and steErr0, which initialize the three output streams of standard input, standard output, and standard error. At this point, System.in, out, and err The initialization process is all clear. The method marked as native is a function implemented by the JVM calling other codes. This has something to do with the bottom layer. I think this feels like the Bootstrap Classloader is actually implemented in C, but it is called by the JVM to load each basic JAR class. In addition, you said that InputStream is an abstract class (interface). In fact, all interface classes and abstract classes can be used as parameters, but the implementation is definitely not implemented by them. They cannot be implemented, but they can be used as parameters. After all, where the parent class appears, the subclasses It can be replaced, so there is no problem here
Because System.in is a static InputStream instance, you can check it out in the java api documentation
First of all, System.in is an object of type InputStream, which is like this in the source code:
It can be seen that System.in belongs to standard input, and data can be entered through the keyboard or other methods.
But in the source code, this object does not have an (explicit) initialization method. By reading the source code, you can find the following method:
Reading the comments shows that this method is used to set
Studying setIn0(in), it can be seen that this method achieves the setting of in by calling the underlying interface. So how is it initialized when the software is running?
There is the following code in the System class:
It can be seen from this code that when the software is running, it first runs the static code block and calls the registerNatives() underlying method to initialize the System class. This method calls the initializeSystemClass() method to initialize the System class. These two steps are Implemented through VM, and then read the initializeSystemClass() method, you can see that three pieces of code are called setIn0, setOut0, and steErr0, which initialize the three output streams of standard input, standard output, and standard error. At this point, System.in, out, and err The initialization process is all clear.
The method marked as native is a function implemented by the JVM calling other codes. This has something to do with the bottom layer. I think this feels like the Bootstrap Classloader is actually implemented in C, but it is called by the JVM to load each basic JAR class.
In addition, you said that InputStream is an abstract class (interface). In fact, all interface classes and abstract classes can be used as parameters, but the implementation is definitely not implemented by them. They cannot be implemented, but they can be used as parameters. After all, where the parent class appears, the subclasses It can be replaced, so there is no problem here