在java语言中,System.out.println("")可以说是java历史上编译次数最多的语句之一,那么,它到底是如何工作的呢?
System.out.println(""),是一个java语句,一般情况下是将传递的参数打印到控制台。
在这条语句中,涉及到三个词:System、out和println。让我们按照顺序,先从System开始。
System,是java.lang包中的一个final类。根据Javadoc介绍,System类包含几个有用的类字段和方法。 它不能被实例化。同时,System类提供的设施包括标准输入、标准输出和错误输出流;访问外部定义的属性和环境变量;一种加载文件和库的方法;以及用于快速赋值数组等一部分的实用方法。如下所示:
/**
* The <code>System</code> class contains several useful class fields
* and methods. It cannot be instantiated.
*
* <p>Among the facilities provided by the <code>System</code> class
* are standard input, standard output, and error output streams;
* access to externally defined properties and environment
* variables; a means of loading files and libraries; and a utility
* method for quickly copying a portion of an array.
*
* @author unascribed
* @since JDK1.0
*/
public final class System {
//此处省略
}
在System类中,一共提供了三个属性,即:
//“标准”输入流。 该流已经打开,准备提供输入数据。 通常,该流对应于键盘输入或由主机环境或用户指定的另一个输入源。
public final static InputStream in = null;
//“标准”输出流。 此流已经打开并准备好接受输出数据。 通常,此流对应于显示输出或由主机环境或用户指定的另一个输出目标。
public final static PrintStream out = null;
//“标准”错误输出流。 此流已经打开并准备好接受输出数据。
public final static PrintStream err = null;
根据文档,可知out是System类的静态成员字段,类型为PrintStream,它在启动就会被实例化,并与主机的标准输出控制台进行映射。该流在实例化后立即打开,并准备好接收输出数据。而字段声明时并未直接实例化PrintStream,那么,PrintStream是如何实例化的呢?
答案是在静态代码块中。在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();
}
从代码块中可以看出,当System类初始化时,会调用native方法registerNatives(),从registerNatives()方法的注释中可以看到,它会调用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 implementatio