java里printInit是什么_print()和println()的区别

源码分析

首先,kotlin中print()方法就是Java中的System.out.print()方法,同样,println()就是System.out.println()。

out是System中的一个静态常量:

public final static PrintStream out;

它的初始化在同类的static块中:

static {

unchangeableProps = initUnchangeableSystemProperties();

props = initProperties();

addLegacyLocaleSystemProperties();

sun.misc.Version.initSystemProperties();

// TODO: Confirm that this isn't something super important.

// sun.misc.VM.saveAndRemoveProperties(props);

lineSeparator = props.getProperty("line.separator");

FileInputStream fdIn = new FileInputStream(FileDescriptor.in);

FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);

FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);

// BEGIN Android-changed: lower buffer size.

// in = new BufferedInputStream(fdIn);

in = new BufferedInputStream(fdIn, 128);

// END Android-changed: lower buffer size.

out = newPrintStream(fdOut, props.getProperty("sun.stdout.encoding"));

err = newPrintStream(fdErr, props.getProperty("sun.stderr.encoding"));

......

}

通过newPrintStream方法创建:

/**

* Create PrintStream for stdout/err based on encoding.

*/

private static PrintStream newPrintStream(FileOutputStream fos, String enc) {

if (enc != null) {

try {

return new PrintStream(new BufferedOutputStream(fos, 128), true, enc);

} catch (UnsupportedEncodingException uee) {}

}

return new PrintStream(new BufferedOutputStream(fos, 128), true);

}

现在我们的重心来到PrintStream中:

private PrintStream(boolean autoFlush, OutputStream out, Charset charset) {

super(out);

this.autoFlush = autoFlush;

// Android-changed: Lazy initialization of charOut and textOut.

// this.charOut = new OutputStreamWriter(this, charset);

// this.textOut = new BufferedWriter(charOut);

this.charset = charset;

}

注意这里的autoFlush传进来的是true。

接下来看一下他们的print方法和println方法:

public void print(Object obj) {

write(String.valueOf(obj));

}

public void println(Object x) {

String s = String.valueOf(x);

synchronized (this) {

print(s);

newLine();

}

}

这两个方法有很多重构方法,所以传参不限于Object。可以看到,println()内部也是调用了print()方法,只不过最后多调用了一个newLine(),我们看一下newLine方法里面:

private void newLine() {

try {

synchronized (this) {

ensureOpen();

// Android-added: Lazy initialization of charOut and textOut.

BufferedWriter textOut = getTextOut();

textOut.newLine();

textOut.flushBuffer();

charOut.flushBuffer();

if (autoFlush)

out.flush();

}

}

catch (InterruptedIOException x) {

Thread.currentThread().interrupt();

}

catch (IOException x) {

trouble = true;

}

}

作为对比,我们看一下单纯的print有什么不一样,也就是write方法:

private void write(String s) {

try {

synchronized (this) {

ensureOpen();

// Android-added: Lazy initialization of charOut and textOut.

BufferedWriter textOut = getTextOut();

textOut.write(s);

textOut.flushBuffer();

charOut.flushBuffer();

if (autoFlush && (s.indexOf('\n') >= 0))

out.flush();

}

}

catch (InterruptedIOException x) {

Thread.currentThread().interrupt();

}

catch (IOException x) {

trouble = true;

}

}

看出不同了吧,单纯的调用write方法只有在输出的字符中含有换行符'\n'才会执行flush方法,而newLine方法则会保证只要autoFlush是true就会执行flush方法,前面说到autoFlush这种情况下传入的都是true,所以区别就在于字符串中是否含有\n,flush方法会打印缓冲区中的信息到控制台,我们就会看到。

PrintStream中的out就是传入的BufferedOutputStream,所以flush就是调用它的方法:

public synchronized void flush() throws IOException {

flushBuffer();

out.flush();

}

它的out就是构造时的FileOutputStream,它的flush方法就是父类OutputStream的flush方法:

/**

* Flushes this output stream and forces any buffered output bytes

* to be written out. The general contract of flush is

* that calling it is an indication that, if any bytes previously

* written have been buffered by the implementation of the output

* stream, such bytes should immediately be written to their

* intended destination.

*

* If the intended destination of this stream is an abstraction provided by

* the underlying operating system, for example a file, then flushing the

* stream guarantees only that bytes previously written to the stream are

* passed to the operating system for writing; it does not guarantee that

* they are actually written to a physical device such as a disk drive.

*

* The flush method of OutputStream does nothing.

*

* @exception IOException if an I/O error occurs.

*/

public void flush() throws IOException {

}

根据注释,这个方法会立即把数据写入到流中,但是不保证会写入到硬件存储设备,因为这是操作系统的职责,它只需要把数据交给和操作系统交互的流中,这部分实现是JVM实现的。这就是为什么正常情况下flush调用之后我们才能看到控制台输出信息的原因。

好了,那我们知道了这个之后,回过头来看,flush前面的代码做了什么。

ensureOpen()确保输入流不能为空,无需赘言。

getTextOut中做了什么:

// BEGIN Android-added: Lazy initialization of charOut and textOut.

private BufferedWriter getTextOut() {

if (textOut == null) {

charOut = charset != null ? new OutputStreamWriter(this, charset) :

new OutputStreamWriter(this);

textOut = new BufferedWriter(charOut);

}

return textOut;

}

// END Android-added: Lazy initialization of charOut and textOut.

charOut把PrintStream封装进OutputStreamWriter中,然后textOut又把charOut封装进BufferedWriter中,然后调用write方法把数据写入,其实就是移交给charOut去做,OutputStreamWriter内部又是通过一个叫StreamEncoder的类去做的,经查询,StreamEncoder的处理过程和我们分析flush的调用过程一样,最终也是调用了JVM的底层方法,把数据压入缓冲区。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值