System.out.println();
初学的时候对这个语句很是困惑,查了很多资料多半都是说的模棱两可,先入为主。但是它到底要怎么去理解呢?
由字面意思我们很容易得出pintln()是一个方法,被System.out的调用,用于向控制台打印输出,但是这里系统是什么?出去又是什么呢?
系统类里有大量的本地方法,是调用本地代码的,这些代码很可能是由虚拟机来调用的。
系统类的开头有一段:
Java代码
静态的 {
registerNatives();
}
这段代码会在虚拟机启动的时候就执行,它在虚拟机里注册系统需要使用的一些本地代码
比如:
Java代码
privatestaticnative属性initProperties(属性道具);
privatestaticnativevoid setOut0(PrintStream out);
在窗户下的话,它就告诉虚拟机到哪个DLL文件里去找相应的实现
Java代码
/ **
*存在以下两种方法,因为in,out和err必须是
*初始化为null。但是,不允许编译器
*内联访问它们,因为它们后来被设置为更合理的值
*通过initializeSystemClass()。
* / privatestatic InputStream nullInputStream()抛出NullPointerException {
if(currentTimeMillis()> 0)
returnnull;
thrownew NullPointerException();
}
也就说in,out,和err初始化为null,然后会在后来由initializeSystemClass()方法类初始化成有意义的值
Java代码
/ **
*初始化系统类。线程初始化后调用。
* / privatestaticvoid initializeSystemClass(){
props = new Properties();
initProperties(道具);
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)); !!! //现在世界已经足够我们可以冒险了
//初始化日志记录配置。尝试{
。java.util.logging.LogManager.getLogManager()readConfiguration();
} catch(Exception ex){
// System.err.println(“无法读取日志记录配置:”);
// ex.printStackTrace(); }
//现在加载zip库以保留java.util.zip.ZipFile
//稍后尝试使用自己加载此库 的LoadLibrary( “拉链”);
//在初始化期间调用的子系统可以调用
// sun.misc.VM.isBooted()以避免做那些应该做的事情
//等到应用程序类加载器设置完毕。sun.misc.VM.booted();
}
输入,输出,犯错就是在以上方法以下三条语句里初始化的。
Java代码
setIn0(new BufferedInputStream(fdIn)); !
setOut0(new PrintStream(new BufferedOutputStream(fdOut,128),true)); !
setErr0(new PrintStream(new BufferedOutputStream(fdErr,128),true)); !
看
Java代码
privatestaticnativevoid setIn0(InputStream in);
这是个本地函数,是前面registerNatives()的时候注册了的。这个函数应该是把实际连接到输入输出设备的句柄传给虚拟机并赋值给IN,OUT,ERR
同学你看错了......
源码是public final static PrintStream out = nullPrintStream();
然后
private static PrintStream nullPrintStream()抛出NullPointerException {
if(currentTimeMillis()> 0){
return null;
}
抛出新的NullPointerException();
}
然后这方法的注释:
/ **
*存在以下两种方法,因为in,out和err必须是
*初始化为null。但是,不允许编译器
*内联访问它们,因为它们后来被设置为更合理的值
*通过initializeSystemClass()。
* /
你没有看全源代码,当导入系统类的时候,已经走了静代代码块完成了out initial beginningization
看源代码System.java
//首次使用时初始化System中的所有插槽。
静态的 {
long hiresFrequency = hiresFrequencyImpl();
if(hiresFrequency == 1000000000L){
nanoType = NANO_RETURN;
nanoAdjust = 0;
nanoIntAdjust = 0;
} else if(hiresFrequency <1000000000L){
nanoAdjust =(double)1000000000L / hiresFrequency;
if(Math.floor(nanoAdjust)== nanoAdjust){
nanoType = NANO_INT_MULTIPLY;
nanoIntAdjust =(long)nanoAdjust;
} else {
nanoType = NANO_MULTIPLY;
nanoIntAdjust = 0;
}
} else {
nanoAdjust = hiresFrequency /(double)1000000000L;
if(Math.floor(nanoAdjust)== nanoAdjust){
nanoType = NANO_DIVIDE;
nanoIntAdjust =(long)nanoAdjust;
} else {
nanoType = NANO_DIVIDE;
nanoIntAdjust = 0;
}
}
//从VM信息中填写属性。
ensureProperties();
//设置标准输入,输出和错误。
//检查默认编码
StringCoding.encode(new char [1],0,1);
err = com.ibm.jvm.io.ConsolePrintStream.localize(new BufferedOutputStream(new FileOutputStream(FileDescriptor.err)),true);
/// **********初始化出在这里**********
out = com.ibm.jvm.io.ConsolePrintStream.localize(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)),true);
in = null;
com.ibm.misc.SystemIntialization.firstChanceHook();
}
解释4
你看的很仔细说的也很对由于java的是支持多线程的,所以标准的输入输出是共享,因此它们必须受到特别的处理,在系统初始化完成之前,线程严禁使用这几个特殊对象;又因为这些对象都是静态的,因此java的的类加载机制会在系统类加载的时候就会初始化,这就造成了一对矛盾;为解决这对矛盾,系统在加载是将它们初始化为空值,等加在完成后,通过天然方法在对它们进行赋值:看看这个:公共最终静态中= nullInputStream()的InputStream;私有静态的InputStream nullInputStream()抛出的NullPointerException {如果(的currentTimeMillis()> 0){返回NULL; 抛出新的NullPointerException(); }在线程初始化完成后,系统会调用方法initializeSystemClass设置这几个特殊对象的值:的FileInputStream fdIn =新的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)); [
解释5
一般解释
println()方法用于打印控件并将其传递给新行。它是PrintStream类的一种方法。对象调用方法。因此out是PrintStream类的对象。System是一个类,它指定要生成输出的硬件(此处)。因此,输出在控制台产生。
在System类中声明的外观如下所示:public static final PrintStreamout,Prinstream类内部是一个具有如下方法签名的println()声明的声明:public void println()。
它可以理解像...
导入 java.io 。*;
类系统 {
public static PrintStream out = new PrintStream();
...
}
class PrintStream {
public void println(String s){...}
public void println(int i){...}
public void println(long l){...}
...
}
System.out的是PrintStream的该类的一个实例。的println 是一个实例方法的PrintStream (实际上的println 该类中有多个方法)。
你可以看到如何出在系统类上的声明:
public final static PrintStream out = null;
在System.out.println中,
所以要打印一些我们需要调用println的东西,它位于PrintStream类中,其对象在System class.Hence System.out.println();
有关更多信息,请参阅以下链接