我们往往在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

System.out.print实现原理猜解的更多相关文章

  1. JVM源码分析之System.currentTimeMillis及nanoTime原理详解

    JDK7和JDK8下的System.nanoTime()输出完全不一样,而且差距还非常大,是不是两个版本里的实现不一样,之前我也没注意过这个细节,觉得非常奇怪,于是自己也在本地mac机器上马上测试了一 ...

  2. python辅助sql手工注入猜解数据库案例分析

    发现存在sql注入漏洞 简单一点可以直接用sqlmap工具暴库 但是如果想深入理解sql注入的原理,可以尝试手工注入,配合python脚本实现手工猜解数据库 首先hachbar开启 获取cms登录后的 ...

  3. WebLogic口令猜解工具【Python脚本】

    WebLogic 默认端口7001 可以通过如下链接访问控制台 http://10.9.1.1:7001/console/login/LoginForm.jsp 写了一个简单的猜解脚本,半成品,做个记 ...

  4. FTP弱口令猜解【python脚本】

    ftp弱口令猜解 python脚本: #! /usr/bin/env python # _*_ coding:utf-8 _*_ import ftplib,time username_list=[' ...

  5. Telnet弱口令猜解【Python脚本】

    telnet 弱口令猜解脚本 测试环境:window2003.centos7 #! /usr/bin/env python # _*_ coding:utf-8 _*_ import telnetli ...

  6. PHPMyAdmin弱口令猜解【Python脚本】

    PHPMyAdmin弱口令猜解 测试截图: 代码片段 #! /usr/bin/env python # _*_ coding:utf-8 _*_ import requests import time ...

  7. 节点地址的函数list_entry()原理详解

    本节中,我们继续讲解,在linux2.4内核下,如果通过一些列函数从路径名找到目标节点. 3.3.1)接下来查看chached_lookup()的代码(namei.c) [path_walk()> ...

  8. WebActivator的实现原理详解

    WebActivator的实现原理详解 文章内容 上篇文章,我们分析如何动态注册HttpModule的实现,本篇我们来分析一下通过上篇代码原理实现的WebActivator类库,WebActivato ...

  9. IIS系统短文件名漏洞猜解过程

    今天看教程的时候,老师关于后台管理说到了短文件名漏洞,我就随便找了个网站猜解,可能是运气太好了,有了这次实践的过程,因为这个漏洞是13年的时候比较火,现在差不多都修复了,抓到一条漏网之鱼, 短文件名漏 ...

随机推荐

  1. spring整合mybatis步骤分析

    1.spring配置datasource bean的时候,不同的数据库连接方式有有不同的datasource实现类. 比如采用c3p0数据库连接池,要用c3p0的datasource实现类 com.m ...

  2. hashcode(),equal()方法深入解析

    首先,想要明白hashCode的作用,必须要先知道Java中的集合. 总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set. 前者集合内的元素是有序的,元素可以重 ...

  3. Nginx 作为反向Proxy 的优化要点

    原文地址:http://my.oschina.net/hyperichq/blog/405421 常用优化要点 当nginx用于反向代理时,每个客户端将使用两个连接: 一个用于响应客户端的请求,另一个 ...

  4. 页面中基于JSTL标签调用函数--之${fn:}内置函数

    调用这样一个头文件<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions " ...

  5. bat薪酬

    三大互联网巨头公司,百度腾讯跟阿里如何划分级别?薪资待遇又有多少?除非身居其位,否则很难探知,但是等你到那个位置知道了,却又不能说,至少不能在公 开场合谈论.接下来就为大家揭秘,百度.阿里与腾讯内部的 ...

  6. 让子弹飞Demo版

    让子弹飞是我非常喜欢的一款游戏.今天的目标就是利用cocos2dx 3.0 和box2d 打造一款这样的类型游戏的Demo版.本来cocos2dx 3.0 已经封装了physicals模块,可是我在使 ...

  7. javascript和python取dict字典对象的不同

    dict1={"a":1,"b":2,"22a":44} JS: dict1.a 和 dict1["a"]都可以 pyt ...

  8. 编写和执行C#代码的插件:CS-Script for Notepad++

    这个插件可以方便得让您在Notepad++编辑器中编辑和执行C#代码(脚本).它具备通用的C#智能感知和项目任务管理功能,方式非常类似于MS Visual Studio.除了这一点,它提供了通用的调试 ...

  9. LigerUI之Grid使用详解(三)——字典数据展示

    一.问题概述 在开发web信息管理系统时,使用Web前端框架可以帮助我们快速搭建一组风格统一的界面效果,而且能够解决大多数浏览器兼容问题,提升开发效率.在关于LigerGrid的前两篇的内容里,给大家 ...

  10. scala 学习笔记十 一 伴生对象

    1.介绍 a.所谓伴生对象就是和某个class同名的object, 并且object 必须和class在同一个scala源文件中. b.在scala中,没有像java中的静态类,静态方法和静态成员等, ...