System类有3个公开的静态常量:
- out
向标准输出流 写入信息 - err
向标准错误流中写入信息 - in
从标准输入流中读取信息
从注释可知,System类的初始化过程分为两个阶段。
- 第一个阶段由类初始化方法完成,在这个方法中
registerNatives()
方法会注册
其他本地方法。 - 第二个阶段由VM完成,在这个阶段VM会调用
System.initializeSystemClass()
↓方法。
/**
* 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));
//本地方 入参是newPrintStream()结果
setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));
... // 其他代码
}
↑可见in、out和err正是在这里设置的
newPrintStream()方法↓
private static PrintStream newPrintStream(FileOutputStream fos, String enc) {
if (enc != null) {
try {
return new PrintStream(new BufferedOutputStream(fos, 128), true, enc);
} catch (UnsupportedEncodingException uee) {}
}
return new PrintStream(new BufferedOutputStream(fos, 128), true);
}
System.out常量是PrintStream类型,Java的io类库使用了装饰器模式,
它内部包装了一个BufferedOutputStream实例。BufferedOutputStream内部又包装了一个FileOutputStream实例。
调用System.out.println(String)方法之后,经过层层包装,最后到达
FileOutputStream类, 它是最里面的, 有个本地方法writeBytes()
// java.io.FileOutputStream
public class FileOutputStream extends OutputStream {
//最终到这个本地方法
private native void writeBytes(byte b[], int off, int len, boolean append)throws IOException;
}
VM
sun.misc.VM类的源代码(VM类属于Oracle私有代码,并没有开源,下面是反编译后
的Java代码):
// sun.misc.VM
public class VM {
... // 其他代码
static {
... // 其他代码
initialize();
}
private static native void initialize();
}
VM类在初始化时调用了initialize()方法。虽然initialize()是本
地方法,但是可以推测正是这个方法调用了System.initializeSystemClass()方法。
虚拟机在开始执行mian方法之前就会加载VM类,并初始化类, 里面的static块就会被执行