我们往往在main中直接调用System.out.print方法来打印,但是其实就这简单的一步里面有很多的玄机,因为main是static的,所以只能调用static的函数,那么print是static的吗?我一直有这个疑问,今天专门查阅了下源码,说下我的理解:(源码只贴出来部分对理解有用的)

源码里面:public final class System 直接在lang包里面。所以可以直接不通过包名就直接调用system类。里面还有:

public final static PrintStream out = nullPrintStream();
............
............

private static PrintStream nullPrintStream() throws NullPointerException {
if (currentTimeMillis() > 0) {
return null;
}
throw new NullPointerException();
}

可以看出out是system的静态成员,所以可以通过system.out直接访问到,但是这时候又有问题了,因为 nullPrintStream()这个函数返回值是null的,怎么可以调用printstream的方法呢。看out的注释:
/**
* The following two methods exist because in, out, and err must be
* initialized to null. The compiler, however, cannot be permitted to
* inline access to them, since they are later set to more sensible values
* by initializeSystemClass().
*/

大概翻译后知道刚开始的时候确实是都是null的,那么什么时候能把out指向标准输出的呢?注释说看initializeSystemClass()这个函数。

/**
* Initialize the system class. Called after thread initialization.
*/
private static void initializeSystemClass() {
props = new Properties();
initProperties(props);
sun.misc.Version.init();

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
.................
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
...............

...............

接着找到FileDescriptor这个类中的静态成员 out:(用自身定义自身)

public static final FileDescriptor out = standardStream(1);

以及standardStream()方法:

private static FileDescriptor standardStream(int fd) {
FileDescriptor desc = new FileDescriptor();
desc.handle = set(fd);
return desc;
}

这时候返回了 handle为1的FileDescriptor; 在传统的unix的系统中,文件描述符为0,1,2分别表示为标准输入,标准输出和错误输出。

最后调用了setout0方法:

private static native void setOut0(PrintStream out);

到这里,setout0是native方法,所以再也追踪不到以后的细节了,而到这时候,out的出路似乎还没有找到。但是。在system类中有setout方法即:

public static void setOut(PrintStream out) {
checkIO();
setOut0(out);
}

调用了setout0()方法,而我们知道setout方法是重置输出流的对象的,因此虽然我们看不到setout0的细节,但是因为setout调用了setout0,我们可以大致猜到setout0是通过调用底层的代码实现对out的流的重定位的,而initializeSystemClass()这个函数也调用了setout0将fd为1的文件封装成文件流,再封装成缓冲流,再封装成打印流,最后通过setout0将out与这个流绑定。这样一切就都说通了。

原文链接:http://www.cnblogs.com/zr-714/archive/2012/03/22/2411926.html

最新文章

  1. 5分钟让你掌握css3阴影、倒影、渐变小技巧!
  2. list点击项高亮其他默认
  3. 【python】datetime获取日期,前一天日期
  4. a标签鼠标经过,字颜色和下划线的颜色都变红
  5. curl 命令行应用
  6. (转)mysql账号权限密码设置方法
  7. LITTLE SHOP OF FLOWERS_DP
  8. iOS打电话、发短信
  9. Permutations java实现
  10. C语言的本质(2)——二进制、八进制、十六进制与十进制
  11. [Oracle] Listener的动态注册
  12. Laravel OAuth2 (一) ---简单获取用户信息
  13. 使用Windows2003创建DHCP服务器 - 进阶者系列 - 学习者系列文章
  14. 使用for循环输出杨辉三角-还是不懂得需要复习
  15. SQL语句详细汇总
  16. Android -- 仿小红书欢迎界面
  17. PYTHON3 中的虚假四舍五入:round()
  18. MongoDb 集群不可用后SECONDARY节点强制启动
  19. python 去重方法
  20. Scala语言笔记 - 第一篇

热门文章

  1. 使用EF Model First创建edmx模型,数据库有数据的情况下,如何同时更新模型和数据库
  2. Spring-Bean配置-使用外部属性文件(转)
  3. zookeeper原理及功能介绍(转)
  4. AlertView动画
  5. MySQL Workbench update语句错误Error Code: 1175.
  6. android 利用 aapt 解析 apk 得到应用名称 包名 版本号 权限等信息
  7. 【BZOJ】【1007】【HNOI2008】水平可见直线
  8. Visual Studio Code 构建C/C++开发环境
  9. strtok()函数
  10. 第二十章 springboot + consul(1)