來源:https://www.cnblogs.com/Mairr/p/7770662.html
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 的索引。此值始終處於 0 到 buf.length 的範圍內;
// 從 buf[0] 到 buf[count-1] 的元素包含從底層輸入流中獲取的緩衝輸入數據。
protected int pos;
// pos = position ,緩衝區中的當前位置,這是將從buf數組中讀取的下一個字符的索引;
// 此值始終處於 0 到 count 的範圍內。如果此值小於 count,則 buf[pos] 將作爲下一個輸入字節;
// 如果此值等於 count,則下一次 read 或 skip 操作需要從包含的輸入流中讀取更多的字節。
protected int markpos = -1;
// 最後一次調用 mark 方法時 pos 字段的值爲 -1; markpos的值始終處於 -1 到 pos 的範圍內,
// 如果輸入流中沒有被標記的位置,則此字段爲 -1;如果輸入流中有被標記的位置,則 buf[markpos] 將用作 reset
// 操作後的第一個輸入字節。如果 markpos 不是 -1,則從位置 buf[markpos] 到 buf[pos-1] 之間的
// 所有字節都必須保留在緩衝區數組中(儘管對 count、pos 和 markpos 的值進行適當調整後,這些字節可能移動到
// 緩衝區數組中的其他位置);除非 pos 與 markpos 的差超過 marklimit,否則不能將其丟棄。
protected int marklimit;
// 調用 mark 方法後,在後續調用 reset 方法失敗之前所允許的最大提前讀取量。
// 只要 pos 與 markpos 之差超過 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()方法;
}
}
}