JDK源码阅读(1)_简介+ java.io

1.简介

  针对这一个版块,主要做一个java8的源码阅读笔记。会对一些在javaWeb中应用比较广泛的java包进行精读,附上注释。对于容易混淆的知识点给出相应的对比分析。
  精读的源码顺序主要如下:

(1)第一部分:这部分是java开发的最常见包和类,要求精读:

  • java.io
  • java.lang
  • java.util

 (2)第二部分:这一部分是java web开发的核心内容之一,要求要有深刻的理解。(包括了java的反射、网络io、非阻塞、并发编程)————某些大牛说,这一部分运用的好坏,掌握的水平高低,会决定一个java开发程员的档次:

  • java.lang.reflect
  • java.net
  • javax.net.*
  • java.nio
  • java.util.concurrent.*

 

  (3)第三部分:这一部分要求不高,进行简单泛读,能看懂、会用即可:

  • java,lang.annotation
  • javax.annotation
  • java.lang.ref
  • java.math
  • java.rmi.*
  • javax.rmi.*
  • java.security.*
  • javax.security.*
  • java.sql
  • javax.sql.*
  • javax.transaction.*
  • java.test
  • java.xml.*
  • org.w3c.dom.*
  • org.xml.sax.*
  • javax.crypto.*
  • javax.imageio.*
  • javax.jws.*
  • java.util.jar
  • java.util.logging
  • java.util.prefs
  • java.util.regex
  • java.util.zip
2.源码阅读:—— day1:(java.io_BufferedInputStream类

(1)java.io——BufferedInputStream类

package java.io;
// java.io包,通过数据流、序列化和文件系统提供系统输入和输出
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
// 导入一个包,这个包运用到了一个多线程的原子更新器
  public class BufferedInputStream extends FilterInputStream {
// 继承fileinputstream,为输入流添加一些功能;使用他防止每次读取时都得进行实际写操作;代表“使用缓冲区”
private static int DEFAULT_BUFFER_SIZE = 8192;
  // 该变量定义了默认的缓冲大小 为8192;
private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
  // 最大长度依然是Integer.MAX_VALUE,并不是Integer.MAX_VALUE-8
protected volatile byte buf[];
  // 存储数据的内部缓冲区数组,必要的时候可以用另外一个大小不同的数组替换它;
  // 注意volatile关键字表示不稳定变量,每次线程存取都应该直接从主程序中读取
  // (作用于多线程环境中)防止主程序值改变,影响其中某个线程的值无法匹配对应而出错;
private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = AtomicReferenceFieldUpdater.newUpdater (BufferedInputStream.class, byte[].class, "buf");
   // 缓存数组的一个原子更新器,该成员变量与buf数组的volatile关键字一起,实现buf数组的原子的更新;
protected int count;
   // 比缓冲区中最后一个有效字节的索引大 1 的索引。此值始终处于 0buf.length 的范围内;
   // 从 buf[0]buf[count-1] 的元素包含从底层输入流中获取的缓冲输入数据。


protected int pos;   // pos = position ,缓冲区中的当前位置,这是将从buf数组中读取的下一个字符的索引;
  // 此值始终处于 0count 的范围内。如果此值小于 count,则 buf[pos] 将作为下一个输入字节;
  // 如果此值等于 count,则下一次 readskip 操作需要从包含的输入流中读取更多的字节。

  
protected int markpos = -1;
  // 最后一次调用 mark 方法时 pos 字段的值为 -1; markpos的值始终处于 -1pos 的范围内,
  // 如果输入流中没有被标记的位置,则此字段为 -1;如果输入流中有被标记的位置,则 buf[markpos] 将用作 reset
  // 操作后的第一个输入字节。如果 markpos 不是 -1,则从位置 buf[markpos]buf[pos-1] 之间的
  // 所有字节都必须保留在缓冲区数组中(尽管对 countposmarkpos 的值进行适当调整后,这些字节可能移动到
  // 缓冲区数组中的其他位置);除非 posmarkpos 的差超过 marklimit,否则不能将其丢弃。


protected int marklimit;   // 调用 mark 方法后,在后续调用 reset 方法失败之前所允许的最大提前读取量。
  // 只要 posmarkpos 之差超过 marklimit,就可以通过将 markpos 设置为 -1 来删除该标记。
private InputStream getInIfOpen() throws IOException { InputStream input = in; if (input == null) throw new IOException("Stream closed"); return input; }
  // 如果输入流为 null ,则抛出传输流关闭“stream closed”的异常
  // 如果输入流不为 null ,则返回输入流,并将数据存储于 input 中

private byte[] getBufIfOpen() throws IOException { byte[] buffer = buf; if (buffer == null) throw new IOException("Stream closed"); return buffer; }   // 创建一个输入流数组,用来保存其参数;当输入保存的参数数组为 null 时,抛出“stream closed”异常,
  // 当不为 null 时,直接返回数组 buffer ,并把输入流存储在数组之中;

public BufferedInputStream(InputStream in) { this(in, DEFAULT_BUFFER_SIZE); // java中,用this引用当前对象; }   // 创建一个缓冲输入流 BufferedInputStream 并保存其数据,即输入流 in ,以便将来使用;
  // 回调缓冲输入流,并且保存其默认参数(缓冲输入流的长度);

public BufferedInputStream(InputStream in, int size) { super(in); // java类中使用super引用父类成分,InputStream是BufferedInputSream的父类; if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); buf = new byte[size]; }
  //
创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in
  // 以便将来使用。创建一个长度为 size 的内部缓冲区数组并将其存储在 buf 中。

private void fill() throws IOException { byte[] buffer = getBufIfOpen(); if (markpos < 0) pos = 0; // 没有标记,总是指向缓冲流的初始位置; else if (pos >= buffer.length) // 位置比缓冲区长度大,缓冲区中没有空间了; if (markpos > 0) { // 抛出缓冲区的前半部分; int sz = pos - markpos; // 字符串数据的长度; System.arraycopy(buffer, markpos, buffer, 0, sz); pos = sz; markpos = 0; // 进行复制和初始化 pos 和 markpos; } else if (buffer.length >= marklimit) { markpos = -1; // 缓冲区太大了,是一个无效的标志位,返回-1; pos = 0; // 降低缓冲区的内容; } else if (buffer.length >= MAX_BUFFER_SIZE) { throw new OutOfMemoryError("Required array size too large"); } else { // 缓冲区进行拓展 int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? pos * 2 : MAX_BUFFER_SIZE; if (nsz > marklimit) nsz = marklimit; byte nbuf[] = new byte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { // 如果这里是不同步的关闭,则不能进行替换; // 注意:如果满了则需要进行拓展变换 // 对于多线程来说,永远不能达到 // 唯一的方式是通过关闭来结束 // 插入 buf == null; throw new IOException("Stream closed"); } buffer = nbuf; } count = pos; int n = getInIfOpen().read(buffer, pos, buffer.length - pos); if (n > 0) count = n + pos; // 数量 }

public synchronized int read() throws IOException { if (pos >= count) { fill(); // 如果位置的值 pos 大于等于 长度数量 count;则调用fill()方法 if (pos >= count) return -1; } return getBufIfOpen()[pos++] & 0xff; }

    // 将字符串读入到数组 array 之中,如果需要,最多进行 1 次;
private int read1(byte[] b, int off, int len) throws IOException { int avail = count - pos; if (avail <= 0) {
       // 如果请求的长度至少和缓冲器一样的大,并且没有进行 mark/reset 操作;
       // 不要急于拷贝不要急于拷贝字节到本地缓冲器之中,如果这样,缓冲流将会无害级联;
if (len >= getBufIfOpen().length && markpos < 0) { return getInIfOpen().read(b, off, len); } fill(); avail = count - pos; if (avail <= 0) return -1; } int cnt = (avail < len) ? avail : len; System.arraycopy(getBufIfOpen(), pos, b, off, cnt); pos += cnt; return cnt; }

   // 以所给的偏移量开始,从输入字节流中,读取到具体字节流数组中; public synchronized int read(byte b[], int off, int len) throws IOException { getBufIfOpen(); // 检查缓冲流是否关闭; if ((off | len | (off + len) | (b.length - (off + len))) < 0) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int n = 0; for (;;) { int nread = read1(b, off + n, len - n); // 读入 if (nread <= 0) return (n == 0) ? nread : n; // 简单的一个选择语句,当n==0返回nread,否则返回n; n += nread; if (n >= len) return n; // 如果输入流没有关闭,但是,已经没有字节可用,则直接返回; InputStream input = in; if (input != null && input.available() <= 0) return n; } }

public synchronized long skip(long n) throws IOException { // n为跳过字节数; getBufIfOpen(); // 检查字符流是否关闭 if (n <= 0) { return 0; } long avail = count - pos; //确定可用长度 if (avail <= 0) { // 如果没有设定标志位置,也没有保存在 buffer 缓冲器中; if (markpos <0) return getInIfOpen().skip(n); // 填满 buffer 缓冲器,用以保存字节,等待重新设置; fill(); avail = count - pos; if (avail <= 0) return 0; } long skipped = (avail < n) ? avail : n; // 选择判断语句,跳过 avail 长度,或者跳过 n 长度; pos += skipped; return skipped; }

//返回可以从该输入流中读取(或跳过)的字节数的估计数,而不需要对该输入流的方法的下一次调用进行阻塞。
//下一个调用可能是同一个线程或另一个线程。此多字节的单个读或跳过不会阻塞,但可能读取或跳过更少字节。
public synchronized int available() throws IOException { int n = count - pos; int avail = getInIfOpen().available(); return n > (Integer.MAX_VALUE - avail) ? Integer.MAX_VALUE : n + avail; }

public synchronized void mark(int readlimit) { marklimit = readlimit; markpos = pos; }
// reset()重置方法; public synchronized void reset() throws IOException { getBufIfOpen(); // 如果缓冲流关闭会抛出异常; if (markpos < 0) // 标志位置小于 0 ,会抛出异常; throw new IOException("Resetting to invalid mark"); pos = markpos; }
public boolean markSupported() { return true; // 测试该输入流支持位置标志; }
  // 关闭此输入流并释放与流相关联的任何系统资源;
  
// 一旦流已经关闭,进一步read(),available(),reset(),或skip()调用会抛出IOException;
   // 关闭先前关闭的流没有效果。
public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { if (bufUpdater.compareAndSet(this, buffer, null)) { InputStream input = in; in = null; if (input != null) input.close(); return; } //其他的情况下,一个新的缓冲区被重新装入,调用fill()方法; } } }

   这一块儿还算比较简单,看看api也差不多,有时间还是应该看看源码,会知其所以然~

原文地址:https://www.cnblogs.com/Mairr/p/7770662.html