JDK源碼閱讀(1)_簡介+ java.io

来源:http://www.cnblogs.com/Mairr/archive/2017/11/15/7770662.html
-Advertisement-
Play Games

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 的索引。此值始終處於 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也差不多,有時間還是應該看看源碼,會知其所以然~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 面試題:寫一個固定容量同步容器,擁有put和get方法,以及getCount方法, 能夠支持2個生產者線程以及10個消費者線程的阻塞調用 有兩種方法 1.使用wait和notify/notifyAll來實現 2.使用Lock和Condition來實現 對比兩種方式,Condition的方式可以更加精 ...
  • 不過大部分手機鬧鐘都不支持這種以小時為單位的周期鬧鈴。所以,我以前每次都是都手動調整鬧鐘時間。總感覺有點 Low!於是,我就寫了個簡單的發郵件的 Lua 腳本,放到樹莓派上作為一個shell命令使用;然後在每周一到周五的9點至23點整點各執行一次發郵件的操作。郵件是發到了我的 QQ 郵箱。收到QQ郵... ...
  • 一萬年太久,只爭朝夕 What JDBC 上部 JDBC(Java DataBase Connectivity)Java 資料庫連接,主要提供編寫 Java 資料庫應用程式的 API 支持 java.sql包中定義的常用的基本的 JDBC API: 類 DriverManager-管理一組 JDBC ...
  • 恢復內容開始 Django 創建第一個項目 本章我們將介紹Django 管理工具及如何使用 Django 來創建項目,第一個項目我們以 HelloWorld 來命令項目。 Django 管理工具 安裝 Django 之後,您現在應該已經有了可用的管理工具 django-admin.py。我們可以使用 ...
  • 一.實現多態所具備的條件有3個: 1.繼承關係 2.子類重寫父類的方法 3.父類的引用指向子類的對象 二.實現一波: 1.編寫Animal類,作為一個父類,有一個name方法,用於給子類重寫. 2.編寫Monkey類繼承Animal類,並重寫父類name方法,擁有自己獨有的climb()方法 3.編 ...
  • 對於所有的Web應用,本質上其實就是一個socket服務端,用戶的瀏覽器其實就是一個socket客戶端。 import socket def f1(request): """ 處理用戶請求,並返回相應的內容 :param request: 用戶請求的所有信息 :return: """ f = ope ...
  • 本文例子完整源碼地址:https://github.com/yu-linfeng/BlogRepositories/tree/master/repositories/Spring%20AOP%E9%AB%98%E7%BA%A7%E2%80%94%E2%80%94%E6%BA%90%E7%A0%81% ...
  • 近日工程中,逐漸感覺到原來複制粘貼代碼的笨重,突然想起以前有人和我說起過Git和SVN之類的版本管理工具。由於平時主要是寫Java代碼,所以能夠在Eclipse中使用SVN工具進行版本管理就可以說是很方便了。今天下午動手解決了這一問題,可以初步使用,但是自己對於版本管理的概念不太熟悉,可能有錯誤,就 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...