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也差不多,有時間還是應該看看源碼,會知其所以然~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM