java.io java.lang java.util (2)第二部分:這一部分是java web開發的核心內容之一,要求要有深刻的理解。(包括了java的反射、網路io、非阻塞、併發編程)————某些大牛說,這一部分運用的好壞,掌握的水平高低,會決定一個java開發程員的檔次: java.lang ...
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()方法; } } }
這一塊兒還算比較簡單,看看api也差不多,有時間還是應該看看源碼,會知其所以然~