一个从0开始的java新生 请多多指教。
相信学过编程的一定对 hello world 不陌生
对Java的实现也不陌生,那么他需要怎么写呢,是这么写的:
public static void main(String[] args) {
System.out.println("hello world");
}
那列位有想过他是怎么实现的吗?
那么,接下来我们来略作了解:
首先,实现的输出语句为:
System.out.println("hello world")
是由4部分组成,分别为 System 类 out 变量 println() 方法 以及变量 "hello world"
首先是 System 类,我们进入到 System 类中 他是这么定义的:
package java.lang;
/**
* The <code>System</code> class contains several useful class fields
* and methods. It cannot be instantiated.
*
* <p>Among the facilities provided by the <code>System</code> class
* are standard input, standard output, and error output streams;
* access to externally defined properties and environment
* variables; a means of loading files and libraries; and a utility
* method for quickly copying a portion of an array.
*
* @author unascribed
* @since JDK1.0
*/
public final class System { ... }
我们发现他是一个被 final 关键字修饰的类,jdk1.8 api 中的定义是:
-
System类包含几个有用的类字段和方法。 它不能被实例化。
-
System类提供的System包括标准输入,标准输出和错误输出流; 访问外部定义的属性和环境变量; 一种加载文件和库的方法; 以及用于快速复制阵列的一部分的实用方法。
然后是 out ,我们进入到 System 类中发现 out 定义的是 PrintStream 类:
/**
* The "standard" output stream. This stream is already
* open and ready to accept output data. Typically this stream
* corresponds to display output or another output destination
* specified by the host environment or user.
* <p>
* For simple stand-alone Java applications, a typical way to write
* a line of output data is:
* <blockquote><pre>
* System.out.println(data)
* </pre></blockquote>
* <p>
* See the <code>println</code> methods in class <code>PrintStream</code>.
*
* @see java.io.PrintStream#println()
* @see java.io.PrintStream#println(boolean)
* @see java.io.PrintStream#println(char)
* @see java.io.PrintStream#println(char[])
* @see java.io.PrintStream#println(double)
* @see java.io.PrintStream#println(float)
* @see java.io.PrintStream#println(int)
* @see java.io.PrintStream#println(long)
* @see java.io.PrintStream#println(java.lang.Object)
* @see java.io.PrintStream#println(java.lang.String)
*/
public final static PrintStream out = null;
进入到 PrintStream 类中发现 他是这么定义的:
package java.io;
/**
* A <code>PrintStream</code> adds functionality to another output stream,
* namely the ability to print representations of various data values
* conveniently. Two other features are provided as well. Unlike other output
* streams, a <code>PrintStream</code> never throws an
* <code>IOException</code>; instead, exceptional situations merely set an
* internal flag that can be tested via the <code>checkError</code> method.
* Optionally, a <code>PrintStream</code> can be created so as to flush
* automatically; this means that the <code>flush</code> method is
* automatically invoked after a byte array is written, one of the
* <code>println</code> methods is invoked, or a newline character or byte
* (<code>'\n'</code>) is written.
*
* <p> All characters printed by a <code>PrintStream</code> are converted into
* bytes using the platform's default character encoding. The <code>{@link
* PrintWriter}</code> class should be used in situations that require writing
* characters rather than bytes.
*
* @author Frank Yellin
* @author Mark Reinhold
* @since JDK1.0
*/
public class PrintStream extends FilterOutputStream
implements Appendable, Closeable
{ ... }
我们发现他是继承于 FilterOutputStream 类,实现接口 Appendable, Closeable,jdk1.8 api 中的定义是:
- A
PrintStream
为另一个输出流添加了功能,即能够方便地打印各种数据值的表示。 还提供了另外两个功能。 与其他输出流不同,PrintStream
从不抛出IOException
; 相反,异常情况只是设置一个可以通过checkError
方法测试的内部标志。 可以选择一个PrintStream
,以便自动刷新; 这意味着flush
字节数组写入方法后自动调用,所述一个println
方法被调用时,或者一个新行字符或字节('\n'
)被写入。 - 由印刷的所有字符
PrintStream
被转换成使用平台的默认字符编码字节。 在需要编写字符而不是字节的情况下,应使用
类。PrintWriter
最后是 println,他是这么定义的:
/**
* Prints a String and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(String)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>String</code> to be printed.
*/
public void println(String x) {
synchronized (this) {
print(x);
newLine();
}
}
最后输出所调用的方法是 PrintStream 类下的 println(String x) 方法,jdk 1.8 api 中的定义是:
- 打印一个字符串,然后终止行。 该方法的行为就像调用
然后print(String)
。println()
-
参数
x
- 要打印的String
。
-
我们在这一步不难发现,其实他是调用的两个方法分别是 print(String s) 方法和 newLine() 方法。那么,我们是不是可以这么理解,即使你调用的是 println 方法进行输出后换行,但是最终也是 先使用 print 方法进行输出 String 后再通过 newLine() 进行换行。
我们继续前进
首先是 print(String s) 方法, 他是这么定义的:
/**
* Prints a string. If the argument is <code>null</code> then the string
* <code>"null"</code> is printed. Otherwise, the string's characters are
* converted into bytes according to the platform's default character
* encoding, and these bytes are written in exactly the manner of the
* <code>{@link #write(int)}</code> method.
*
* @param s The <code>String</code> to be printed
*/
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
在这一步中进行了 null 值判断,如果是 null 值则赋值为字符串 "null",jdk 1.8 api 中的定义是:
- public void print(String s)
-
打印字符串。 如果参数是
null
那么打印字符串"null"
。 否则,字符串的字符将根据平台的默认字符编码转换为字节,并且这些字节以
的方式写入。write(int)
参数
s
- 要打印的String
-
进行 null
值判断后,调用
write(String s) 方法,再通过 write 方法输出 String 。
我们来看一下 write(String s),他是这么定义的:
private void write(String s) {
try {
synchronized (this) {
ensureOpen();
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;
}
}
很奇怪啊,竟然没有注释!!!为什么会这样,这谁看的懂!!!虽然英语是战五渣!但是并不能妨碍我一颗躁动的心啊!!!!!!
这个方法就比较绕,调用了四五个方法还有变量赋值,就不一一去动了,jdk 1.8 api 中的定义是:
- 啊,没有!下一位
这样的话我们直接跳到,这一行
textOut.write(s);
textOut 是谁?BufferedWriter 类!
/**
* Track both the text- and character-output streams, so that their buffers
* can be flushed without flushing the entire stream.
*/
private BufferedWriter textOut;
BufferedWriter 类!是谁!!!他来了,他来了,他骑着毛驴儿跑来了。他是这样子的:
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.io;
/**
* Writes text to a character-output stream, buffering characters so as to
* provide for the efficient writing of single characters, arrays, and strings.
*
* <p> The buffer size may be specified, or the default size may be accepted.
* The default is large enough for most purposes.
*
* <p> A newLine() method is provided, which uses the platform's own notion of
* line separator as defined by the system property <tt>line.separator</tt>.
* Not all platforms use the newline character ('\n') to terminate lines.
* Calling this method to terminate each output line is therefore preferred to
* writing a newline character directly.
*
* <p> In general, a Writer sends its output immediately to the underlying
* character or byte stream. Unless prompt output is required, it is advisable
* to wrap a BufferedWriter around any Writer whose write() operations may be
* costly, such as FileWriters and OutputStreamWriters. For example,
*
* <pre>
* PrintWriter out
* = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
* </pre>
*
* will buffer the PrintWriter's output to the file. Without buffering, each
* invocation of a print() method would cause characters to be converted into
* bytes that would then be written immediately to the file, which can be very
* inefficient.
*
* @see PrintWriter
* @see FileWriter
* @see OutputStreamWriter
* @see java.nio.file.Files#newBufferedWriter
*
* @author Mark Reinhold
* @since JDK1.1
*/
public class BufferedWriter extends Writer { ... }
继承于 Writer 类,jdk 1.8 api 的定义:
-
public class BufferedWriter extends Writer
将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。
提供了一个newLine()方法,它使用平台自己的系统属性line.separator定义的行分隔符概念。 并非所有平台都使用换行符('\ n')来终止行。 因此,调用此方法来终止每个输出行,因此优选直接写入换行符。
一般来说,Writer将其输出立即发送到底层字符或字节流。 除非需要提示输出,否则建议将BufferedWriter包装在其write()操作可能很昂贵的Writer上,例如FileWriters和OutputStreamWriters。 例如,
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("foo.out")));
将缓冲PrintWriter的输出到文件。 没有缓冲,每次调用print()方法都会使字符转换为字节,然后立即写入文件,这可能非常低效。从以下版本开始:
JDK1.1
另请参见:
PrintWriter
,FileWriter
,OutputStreamWriter
,Files.newBufferedWriter(java.nio.file.Path, java.nio.charset.Charset, java.nio.file.OpenOption...)
有点恐怖啊,兄嘚,那么继续,下面就是 write(String str) 方法,他是这样子的:
重点注意,这个方法是在 Writer 类下的一个方法
/**
* Writes a string.
*
* @param str
* String to be written
*
* @throws IOException
* If an I/O error occurs
*/
public void write(String str) throws IOException {
write(str, 0, str.length());
}
他还会抛异常!他升华了!这就是为什么在 PrintStream 类下的 write(String s) 方法进行 try{}catch{} 了,jdk 1.8 api 中的定义是
- public void write(String str) throws IOException
-
写一个字符串
参数
str
- 要写入的字符串异常
IOException
- 如果发生I / O错误
-
这个方法其实就是给一个默认值去调用 write(String s, int off, int len) 方法。
跳转回 BufferedWriter 中的 write(String s, int off, int len) 方法,他是这样子的:
/**
* Writes a portion of a String.
*
* <p> If the value of the <tt>len</tt> parameter is negative then no
* characters are written. This is contrary to the specification of this
* method in the {@linkplain java.io.Writer#write(java.lang.String,int,int)
* superclass}, which requires that an {@link IndexOutOfBoundsException} be
* thrown.
*
* @param s String to be written
* @param off Offset from which to start reading characters
* @param len Number of characters to be written
*
* @exception IOException If an I/O error occurs
*/
public void write(String s, int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
int b = off, t = off + len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
s.getChars(b, b + d, cb, nextChar);
b += d;
nextChar += d;
if (nextChar >= nChars)
flushBuffer();
}
}
}
这个方法主要是将 String 字符串转换成 char 数组 写入存放,jdk 1.8 api 的定义:
- public void write(String s, int off, int len) throws IOException
- 写一个字符串的一部分。
如果len参数的值为负,则不会写入任何字符。 这与superclass中的这种方法的规范相反 , superclass要求抛出一个
IndexOutOfBoundsException
。重写:
参数
s
- 要写入的字符串off
- 开始读取字符的偏移量len
- 要写入的字符数异常
IOException
- 如果发生I / O错误
- 写一个字符串的一部分。
然后进行刷新,他是这样子的:
textOut.flushBuffer();
方法是这样子的:
/**
* Flushes the output buffer to the underlying character stream, without
* flushing the stream itself. This method is non-private only so that it
* may be invoked by PrintStream.
*/
void flushBuffer() throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
}
}
将输出缓冲区刷新到底层字符流,而不刷新流本身。 这个方法是非私有的,所以它可以被 PrintStream 调用。jdk 1.8 api 中的定义为:
没有!!!干!!!闹着玩呢!!!
输出!他!终于来了!历经存放、刷新字符流,终于可以打印了!!!他是这样的:
charOut.flushBuffer();
charOut 是谁?定义的哪个类? OutputStreamWriter 类,进入后是这个样子的:
/*
* Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.io;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import sun.nio.cs.StreamEncoder;
/**
* An OutputStreamWriter is a bridge from character streams to byte streams:
* Characters written to it are encoded into bytes using a specified {@link
* java.nio.charset.Charset charset}. The charset that it uses
* may be specified by name or may be given explicitly, or the platform's
* default charset may be accepted.
*
* <p> Each invocation of a write() method causes the encoding converter to be
* invoked on the given character(s). The resulting bytes are accumulated in a
* buffer before being written to the underlying output stream. The size of
* this buffer may be specified, but by default it is large enough for most
* purposes. Note that the characters passed to the write() methods are not
* buffered.
*
* <p> For top efficiency, consider wrapping an OutputStreamWriter within a
* BufferedWriter so as to avoid frequent converter invocations. For example:
*
* <pre>
* Writer out
* = new BufferedWriter(new OutputStreamWriter(System.out));
* </pre>
*
* <p> A <i>surrogate pair</i> is a character represented by a sequence of two
* <tt>char</tt> values: A <i>high</i> surrogate in the range '\uD800' to
* '\uDBFF' followed by a <i>low</i> surrogate in the range '\uDC00' to
* '\uDFFF'.
*
* <p> A <i>malformed surrogate element</i> is a high surrogate that is not
* followed by a low surrogate or a low surrogate that is not preceded by a
* high surrogate.
*
* <p> This class always replaces malformed surrogate elements and unmappable
* character sequences with the charset's default <i>substitution sequence</i>.
* The {@linkplain java.nio.charset.CharsetEncoder} class should be used when more
* control over the encoding process is required.
*
* @see BufferedWriter
* @see OutputStream
* @see java.nio.charset.Charset
*
* @author Mark Reinhold
* @since JDK1.1
*/
public class OutputStreamWriter extends Writer { ... }
我讲解不如官方文档来的硬气,那么 jdk 1.8 api 的定义:
-
public class OutputStreamWriter extends Writer
OutputStreamWriter是字符的桥梁流以字节流:向其写入的字符编码成使用指定的字节charset
。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。每次调用write()方法都会使编码转换器在给定字符上被调用。 所得到的字节在写入底层输出流之前累积在缓冲区中。 可以指定此缓冲区的大小,但是默认情况下它大部分用于大多数目的。 请注意,传递给write()方法的字符不会缓冲。
为了最大的效率,请考虑在BufferedWriter中包装一个OutputStreamWriter,以避免频繁的转换器调用。 例如:
Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
代理对是由两个char值的序列表示的字符 :“\ uD800”到“\ uDBFF”范围内的高代理,后跟“\ uDC00”到“\ uDFFF”范围内的低代理。
一个畸形的替代元素是一个高替代品,其后没有高替代品的低替代品或低替代品。
这个类总是用字符集的默认替换序列替换格式不正确的代理元素和不可映射的字符序列 。 当需要对编码过程进行更多控制时,应使用CharsetEncoder类。
从以下版本开始:
JDK1.1
另请参见:
怎么样,够官方吧。咱们继续往下走,flushBuffer() 方法是这样子的:
/**
* Flushes the output buffer to the underlying byte stream, without flushing
* the byte stream itself. This method is non-private only so that it may
* be invoked by PrintStream.
*/
void flushBuffer() throws IOException {
se.flushBuffer();
}
发现他也是调用了一个方法,se 是谁?se 是 StreamEncoder 类,他是这样子的:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package sun.nio.cs;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
public class StreamEncoder extends Writer { ... }
来看一下 jdk 1.8 api 的定义:
没有,在此版本 api 中没有发现此类的讲解,StreamEncoder 是什么呢?
这边找到一个博客的讲解: JAVA基础知识之StreamEncoder流_咕噜是个胖子-CSDN博客
StreamEncoder 类 的 flushBuffer() 方法是这样的:
public void flushBuffer() throws IOException {
synchronized(this.lock) {
if (this.isOpen()) {
this.implFlushBuffer();
} else {
throw new IOException("Stream closed");
}
}
}
我们略过 isOpen() 判断,进入到 implFlushBuffer() 方法,是这样的:
void implFlushBuffer() throws IOException {
if (this.bb.position() > 0) {
this.writeBytes();
}
}
我们终于来到输出的位置了,太难了,哭晕在厕所的 A4 纸上 T.T
writeBytes() 方法是长这个样子的:
private void writeBytes() throws IOException {
this.bb.flip();
int var1 = this.bb.limit();
int var2 = this.bb.position();
assert var2 <= var1;
int var3 = var2 <= var1 ? var1 - var2 : 0;
if (var3 > 0) {
if (this.ch != null) {
assert this.ch.write(this.bb) == var3 : var3;
} else {
this.out.write(this.bb.array(), this.bb.arrayOffset() + var2, var3);
}
}
this.bb.clear();
}
bb 是谁?好奇怪的名字。。 他是谁呢? 他是 ByteBuffer 类,他是这样子的:
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
// -- This file was mechanically generated: Do not edit! -- //
package java.nio;
/**
* A byte buffer.
*
* <p> This class defines six categories of operations upon
* byte buffers:
*
* <ul>
*
* <li><p> Absolute and relative {@link #get() <i>get</i>} and
* {@link #put(byte) <i>put</i>} methods that read and write
* single bytes; </p></li>
*
* <li><p> Relative {@link #get(byte[]) <i>bulk get</i>}
* methods that transfer contiguous sequences of bytes from this buffer
* into an array; </p></li>
*
* <li><p> Relative {@link #put(byte[]) <i>bulk put</i>}
* methods that transfer contiguous sequences of bytes from a
* byte array or some other byte
* buffer into this buffer; </p></li>
*
*
* <li><p> Absolute and relative {@link #getChar() <i>get</i>}
* and {@link #putChar(char) <i>put</i>} methods that read and
* write values of other primitive types, translating them to and from
* sequences of bytes in a particular byte order; </p></li>
*
* <li><p> Methods for creating <i><a href="#views">view buffers</a></i>,
* which allow a byte buffer to be viewed as a buffer containing values of
* some other primitive type; and </p></li>
*
*
* <li><p> Methods for {@link #compact compacting}, {@link
* #duplicate duplicating}, and {@link #slice slicing}
* a byte buffer. </p></li>
*
* </ul>
*
* <p> Byte buffers can be created either by {@link #allocate
* <i>allocation</i>}, which allocates space for the buffer's
*
*
* content, or by {@link #wrap(byte[]) <i>wrapping</i>} an
* existing byte array into a buffer.
*
*
*
* <a name="direct"></a>
* <h2> Direct <i>vs.</i> non-direct buffers </h2>
*
* <p> A byte buffer is either <i>direct</i> or <i>non-direct</i>. Given a
* direct byte buffer, the Java virtual machine will make a best effort to
* perform native I/O operations directly upon it. That is, it will attempt to
* avoid copying the buffer's content to (or from) an intermediate buffer
* before (or after) each invocation of one of the underlying operating
* system's native I/O operations.
*
* <p> A direct byte buffer may be created by invoking the {@link
* #allocateDirect(int) allocateDirect} factory method of this class. The
* buffers returned by this method typically have somewhat higher allocation
* and deallocation costs than non-direct buffers. The contents of direct
* buffers may reside outside of the normal garbage-collected heap, and so
* their impact upon the memory footprint of an application might not be
* obvious. It is therefore recommended that direct buffers be allocated
* primarily for large, long-lived buffers that are subject to the underlying
* system's native I/O operations. In general it is best to allocate direct
* buffers only when they yield a measureable gain in program performance.
*
* <p> A direct byte buffer may also be created by {@link
* java.nio.channels.FileChannel#map mapping} a region of a file
* directly into memory. An implementation of the Java platform may optionally
* support the creation of direct byte buffers from native code via JNI. If an
* instance of one of these kinds of buffers refers to an inaccessible region
* of memory then an attempt to access that region will not change the buffer's
* content and will cause an unspecified exception to be thrown either at the
* time of the access or at some later time.
*
* <p> Whether a byte buffer is direct or non-direct may be determined by
* invoking its {@link #isDirect isDirect} method. This method is provided so
* that explicit buffer management can be done in performance-critical code.
*
*
* <a name="bin"></a>
* <h2> Access to binary data </h2>
*
* <p> This class defines methods for reading and writing values of all other
* primitive types, except <tt>boolean</tt>. Primitive values are translated
* to (or from) sequences of bytes according to the buffer's current byte
* order, which may be retrieved and modified via the {@link #order order}
* methods. Specific byte orders are represented by instances of the {@link
* ByteOrder} class. The initial order of a byte buffer is always {@link
* ByteOrder#BIG_ENDIAN BIG_ENDIAN}.
*
* <p> For access to heterogeneous binary data, that is, sequences of values of
* different types, this class defines a family of absolute and relative
* <i>get</i> and <i>put</i> methods for each type. For 32-bit floating-point
* values, for example, this class defines:
*
* <blockquote><pre>
* float {@link #getFloat()}
* float {@link #getFloat(int) getFloat(int index)}
* void {@link #putFloat(float) putFloat(float f)}
* void {@link #putFloat(int,float) putFloat(int index, float f)}</pre></blockquote>
*
* <p> Corresponding methods are defined for the types <tt>char</tt>,
* <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and <tt>double</tt>. The index
* parameters of the absolute <i>get</i> and <i>put</i> methods are in terms of
* bytes rather than of the type being read or written.
*
* <a name="views"></a>
*
* <p> For access to homogeneous binary data, that is, sequences of values of
* the same type, this class defines methods that can create <i>views</i> of a
* given byte buffer. A <i>view buffer</i> is simply another buffer whose
* content is backed by the byte buffer. Changes to the byte buffer's content
* will be visible in the view buffer, and vice versa; the two buffers'
* position, limit, and mark values are independent. The {@link
* #asFloatBuffer() asFloatBuffer} method, for example, creates an instance of
* the {@link FloatBuffer} class that is backed by the byte buffer upon which
* the method is invoked. Corresponding view-creation methods are defined for
* the types <tt>char</tt>, <tt>short</tt>, <tt>int</tt>, <tt>long</tt>, and
* <tt>double</tt>.
*
* <p> View buffers have three important advantages over the families of
* type-specific <i>get</i> and <i>put</i> methods described above:
*
* <ul>
*
* <li><p> A view buffer is indexed not in terms of bytes but rather in terms
* of the type-specific size of its values; </p></li>
*
* <li><p> A view buffer provides relative bulk <i>get</i> and <i>put</i>
* methods that can transfer contiguous sequences of values between a buffer
* and an array or some other buffer of the same type; and </p></li>
*
* <li><p> A view buffer is potentially much more efficient because it will
* be direct if, and only if, its backing byte buffer is direct. </p></li>
*
* </ul>
*
* <p> The byte order of a view buffer is fixed to be that of its byte buffer
* at the time that the view is created. </p>
*
*
*
*
* <h2> Invocation chaining </h2>
*
* <p> Methods in this class that do not otherwise have a value to return are
* specified to return the buffer upon which they are invoked. This allows
* method invocations to be chained.
*
*
* The sequence of statements
*
* <blockquote><pre>
* bb.putInt(0xCAFEBABE);
* bb.putShort(3);
* bb.putShort(45);</pre></blockquote>
*
* can, for example, be replaced by the single statement
*
* <blockquote><pre>
* bb.putInt(0xCAFEBABE).putShort(3).putShort(45);</pre></blockquote>
*
*
*
* @author Mark Reinhold
* @author JSR-51 Expert Group
* @since 1.4
*/
public abstract class ByteBuffer
extends Buffer
implements Comparable<ByteBuffer>
{ ... }
jdk 1.8 api 的定义:
-
public abstract class ByteBuffer extends Buffer implements Comparable<ByteBuffer>
一个字节缓冲区。这个类在字节缓冲区中定义了六类操作:
-
相对
bulk get
方法将连续的字节序列从该缓冲区传输到数组中; -
相对
bulk put
方法,将字节数组或其他字节缓冲区的连续字节序列传输到此缓冲区中; -
用于创建view buffers的方法,其允许将字节缓冲器视为包含某些其他原始类型的值的缓冲器; 和
-
方法
compacting
,duplicating
和slicing
一个字节的缓冲区。
字节缓冲区可以由
allocation
创建,它为缓冲区的内容分配空间,或者通过wrapping
将现有的字节数组分配到缓冲区中。直接与非直接缓冲区
字节缓冲区是直接 或非直接的 。 给定一个直接字节缓冲区,Java虚拟机将尽力在其上直接执行本地I / O操作。 也就是说,它将尝试避免在每次调用其中一个底层操作系统的本机I / O操作之前(或之后)将缓冲区的内容复制到(或从)中间缓冲区。
可以通过调用此类的
allocateDirect
工厂方法来创建直接字节缓冲区。 此方法返回的缓冲区通常比非直接缓冲区具有更高的分配和释放成本。 直接缓冲区的内容可能驻留在正常的垃圾回收堆之外,因此它们对应用程序的内存占用的影响可能不明显。 因此,建议直接缓冲区主要用于受基础系统本机I / O操作影响的大型长寿命缓冲区。 一般来说,最好只在产生程序性能可测量的增益时才分配直接缓冲区。直接字节缓冲区也可以由文件的
mapping
直接创建到内存区域。 Java平台的实现可以可选地支持通过JNI从本地代码创建直接字节缓冲器。 如果这些缓冲区之一的实例指的是存储器的不可访问的区域,则访问该区域的尝试将不会改变缓冲区的内容,并且将导致在访问时或之后的某个未指定的异常时间。字节缓冲区是直接还是非直接可以通过调用其
isDirect
方法来确定 。 提供了这种方法,使得可以在性能关键代码中进行显式缓冲区管理。访问二进制数据
该类定义了用于读取和写入所有其他原始类型的值的方法,但boolean除外。 原始值根据缓冲区的当前字节顺序转换为(或从)字节序列,可以通过
order
方法检索和修改。 特定字节顺序由ByteOrder
类的实例表示。 字节缓冲区的初始顺序始终为BIG_ENDIAN
。对于访问异构二进制数据,即不同类型的值序列,该类定义了每个类型的绝对和相对get和put方法族。 例如,对于32位浮点值,此类定义:
float
getFloat()
floatgetFloat(int index)
voidputFloat(float f)
voidputFloat(int index, float f)
相应的方法被用于类型char,short,int,long和double限定。 绝对get和put方法的索引参数是以字节为单位,而不是读取或写入的类型。
对于访问同构二进制数据,即相同类型的值的序列,此类定义可以创建给定字节缓冲区的视图的方法。 视图缓冲区只是另一个缓冲区,其内容由字节缓冲区支持。 对字节缓冲区内容的更改将在视图缓冲区中可见,反之亦然; 两个缓冲区的位置,极限和标记值是独立的。 例如,
asFloatBuffer
方法创建了由调用该方法的字节缓冲区支持的FloatBuffer
类的实例。 相应的视图创建方法的各类char,short,int,long和double限定。与上述类型特定的get和put方法相比,查看缓冲区有三个重要的优点:
-
视图缓冲区的索引不是以字节为单位,而是根据其值的类型特定大小;
-
视图缓冲器提供相对的批量获取和放置方法,该方法可以在缓冲区和数组之间传递连续序列值或者相同类型的其他缓冲区; 和
-
视图缓冲区可能会更有效率,因为只有当它的后备字节缓冲区是直接的时才是直接的。
在创建视图时,视图缓冲区的字节顺序被固定为其字节缓冲区的字节顺序。
调用链接
指定此类中没有值返回值的方法返回调用它们的缓冲区。 这允许方法调用被链接。 语句序列
bb.putInt(0xCAFEBABE); bb.putShort(3); bb.putShort(45);
bb.putInt(0xCAFEBABE).putShort(3).putShort(45);
从以下版本开始:
1.4
是不是感觉好多?但是也要复制一下,这样会更有助于理解,我们进入到 flip() 方法发现,他其实就是赋值,他长这样子:
/**
* Flips this buffer. The limit is set to the current position and then
* the position is set to zero. If the mark is defined then it is
* discarded.
*
* <p> After a sequence of channel-read or <i>put</i> operations, invoke
* this method to prepare for a sequence of channel-write or relative
* <i>get</i> operations. For example:
*
* <blockquote><pre>
* buf.put(magic); // Prepend header
* in.read(buf); // Read data into rest of buffer
* buf.flip(); // Flip buffer
* out.write(buf); // Write header + data to channel</pre></blockquote>
*
* <p> This method is often used in conjunction with the {@link
* java.nio.ByteBuffer#compact compact} method when transferring data from
* one place to another. </p>
*
* @return This buffer
*/
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
上面有讲解哦。回头看一下就知道啦,嘻嘻(●'◡'●)。
经过一系列的判断最后会进入到 out.write(byte b[], int off, int len) 方法,问题又来了,out 又是谁?哪个类?他是 OutputStream 类,是这个样子的:
/*
* Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.io;
/**
* This abstract class is the superclass of all classes representing
* an output stream of bytes. An output stream accepts output bytes
* and sends them to some sink.
* <p>
* Applications that need to define a subclass of
* <code>OutputStream</code> must always provide at least a method
* that writes one byte of output.
*
* @author Arthur van Hoff
* @see java.io.BufferedOutputStream
* @see java.io.ByteArrayOutputStream
* @see java.io.DataOutputStream
* @see java.io.FilterOutputStream
* @see java.io.InputStream
* @see java.io.OutputStream#write(int)
* @since JDK1.0
*/
public abstract class OutputStream implements Closeable, Flushable { ... }
jdk 1.8 api 的定义:
-
public abstract class OutputStream extends Object implements Closeable, Flushable
这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。需要定义
OutputStream
子类的应用OutputStream
必须至少提供一个写入一个字节输出的方法。从以下版本开始:
JDK1.0
另请参见:
BufferedOutputStream
,ByteArrayOutputStream
,DataOutputStream
,FilterOutputStream
,InputStream
,write(int)
被忽悠了!this.out 竟然调用的是 PrintStream 类,write(byte buf[], int off, int len) 方法!!!啊!!!!!!!!!!!!!!!!!!我要裂开了!!!!!!!!!!
他是这样子的:
/**
* Writes <code>len</code> bytes from the specified byte array starting at
* offset <code>off</code> to this stream. If automatic flushing is
* enabled then the <code>flush</code> method will be invoked.
*
* <p> Note that the bytes will be written as given; to write characters
* that will be translated according to the platform's default character
* encoding, use the <code>print(char)</code> or <code>println(char)</code>
* methods.
*
* @param buf A byte array
* @param off Offset from which to start taking bytes
* @param len Number of bytes to write
*/
public void write(byte buf[], int off, int len) {
try {
synchronized (this) {
ensureOpen();
out.write(buf, off, len);
if (autoFlush)
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
上边有讲解哦,就不讲解了。最后!兜兜转转调用到了 FileOutputStream 类的,write(byte b[], int off, int len) 方法,为什么不写了呢?也要复习 api 的嘛,就到这里啦!bye~
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this file output stream.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @exception IOException if an I/O error occurs.
*/
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
}