zoukankan      html  css  js  c++  java
  • System.out.print实现原理猜解

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

  • 相关阅读:
    mysql复制那点事
    全排列问题
    56. Merge Interval
    2. Add Two Numbers
    20. Valid Parentheses
    121. Best Time to Buy and Sell Stock
    120. Triangle
    96. Unique Binary Search Trees
    91. Decode Ways
    72. Edit Distance
  • 原文地址:https://www.cnblogs.com/flying607/p/3419240.html
Copyright © 2011-2022 走看看