zoukankan      html  css  js  c++  java
  • 盘一盘 System.out.println()

    System.out.println("Hello World")是大部分程序员入门的第一行代码,也可以说是程序员们最熟悉的一行代码。大家真的深入研究过System.out.println()么?今天就来盘一盘System.out.println()!
     

    System是个啥?

    System作为Java.lang包中一个final类,早在JDK1.0中就存在其中,可谓基石也。
     

    再来看看out

    out是System中的一个静态的数据成员,但这个成员不是基本类,而是java.io.PrintStream类的对象。out被关键字static修饰,我们可以直接通过System.out来引用,而无须先建立对象。
    public final static PrintStream out = null;

    out在系统类初始化时被实例化,配置输出在控制台上。

    private static void initializeSystemClass() {
    
        props = new Properties();
        initProperties(props);  // initialized by the VM
    
        sun.misc.VM.saveAndRemoveProperties(props);
    
    
        lineSeparator = props.getProperty("line.separator");
        sun.misc.Version.init();
    
    
        FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
        // 获取 FileDescriptor中的静态成员 out并创建对应的文件输出流。out是一个 FileDescriptor对象,它是"标准输出(屏幕)"的标识符。
        FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
        FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
        setIn0(new BufferedInputStream(fdIn));
        //标准输出编码
        setOut0(newPrintStream(fdOut, props.getProperty("sun.stdout.encoding")));
        setErr0(newPrintStream(fdErr, props.getProperty("sun.stderr.encoding")));
    
        loadLibrary("zip");
    
        Terminator.setup();
    
        sun.misc.VM.initializeOSEnvironment();
    
        Thread current = Thread.currentThread();
        current.getThreadGroup().add(current);
    
    
        setJavaLangAccess();
    
    
        sun.misc.VM.booted();
    }
    
    //native方法 输出
    private static native void setOut0(PrintStream out);

    out对象是可以自定义的。开发人员可以在执行期间对out对象进行修改。

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

    例:修改out输出路径,将结果以文档形式输出

    public class ModifyOut {
      public static void main(String args[]) {
           System.setOut(new PrintStream(new FileOutputStream("ModifyOut.txt")));
           System.out.println("out输出已经重定向!");
      }
    }

    最后是printl()

    println()中的传入参数包含了各种各样的参数类型,枚举了一下。
    java.io.PrintStream#println()
    java.io.PrintStream#println(boolean)
    java.io.PrintStream#println(char)
    java.io.PrintStream#println(char[])
    java.io.PrintStream#println(double)
    java.io.PrintStream#println(float)
    java.io.PrintStream#println(int)
    java.io.PrintStream#println(long)
    java.io.PrintStream#println(java.lang.Object)
    java.io.PrintStream#println(java.lang.String)

    各种参数的println()方法内容大同小异,这里以println(Object x)为例,盘一下println()中都干了些啥。

    public void println(Object x) {
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
        }
    }

    使用println()方法中的大部分参数,在执行write(s)方法前,通通被转换成String类型。仅char[] 并没有转换成String类型。原因嘛。嘿嘿,String类型就是char[]实现的啊。

    public void print(String s) {
        if (s == null) {
            s = "null";
        }
        // 传入的参数在执行write(s)方法前,通通都被转成String类型。
        write(s);
    }

    操劳多种类型进行String类型转换,就是为了这步write(String s)方法集中统一处理

    private void write(String s) {
        try {
            synchronized (this) {    
                //检查确认当前流尚未关闭
                ensureOpen();
                //输出传入的字符串
                textOut.write(s);
                // 刷新此输出流并强制写出所有缓冲的输出字节。
                textOut.flushBuffer();
                charOut.flushBuffer();
                if (autoFlush && (s.indexOf('
    ') >= 0))
                    out.flush();
            }
        }
        catch (InterruptedIOException x) {
            Thread.currentThread().interrupt();
        }
        catch (IOException x) {
            trouble = true;
        }
    }
    /**
    * writeBuffer的大小 默认为1024
    */
    private static final int WRITE_BUFFER_SIZE = 1024;
    
    public void write(String str) throws IOException {
        write(str, 0, str.length());
    }
    
    public void write(String str, int off, int len) throws IOException {
        synchronized (lock) {
            char cbuf[];
            if (len <= WRITE_BUFFER_SIZE) {
                if (writeBuffer == null) {
                    writeBuffer = new char[WRITE_BUFFER_SIZE];
                }
                cbuf = writeBuffer;
            } else {    // Don't permanently allocate very large buffers.
                cbuf = new char[len];
            }
            str.getChars(off, (off + len), cbuf, 0);
    
            // 输出字符数组(说了这么多,最后处理的还是字符组)
            write(cbuf, 0, len);
        }
    }
    
    //  将字符数组buffer写入到输出流中,offset是从buffer中读取数据的起始偏移位置,len是读取的长度。
    abstract public void write(char cbuf[], int off, int len) throws IOException;
  • 相关阅读:
    apply()和call()的区别
    强制类型转换
    浮动理解
    清除浮动的方式
    五大主流浏览器及四大内核
    CSS引入方式
    js构建类的方法
    web前端与后端的理解区分
    Java的API及Object
    面向对象之this关键字
  • 原文地址:https://www.cnblogs.com/LemonFive/p/11209806.html
Copyright © 2011-2022 走看看