最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

通過JDK源碼學習InputStream詳解

 更新時間:2017年11月08日 08:41:00   作者:汪洋之舟---seaboat  
InputStream抽象類是所有字節(jié)輸入流的類的超類。這篇文章主要給大家介紹了關(guān)于通過JDK源碼學習InputStream的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。

概況

本文主要給大家介紹了通過JDK源碼學習InputStream的相關(guān)內(nèi)容,JDK 給我們提供了很多實用的輸入流 xxxInputStream,而 InputStream 是所有字節(jié)輸入流的抽象。包括 ByteArrayInputStream 、FilterInputStream 、BufferedInputStream 、DataInputStream 和 PushbackInputStream 等等。下面話不多說了,來一起看看詳細的介紹吧。

如何閱讀JDK源碼。

以看核心虛擬機(hotspot)code為例介紹。

1)熟悉虛擬機原理。調(diào)bug可以不懂原理,但是看code必須懂原理,從code里面看原理,基本不可能。hotspot的code寫的挺亂的,想直接通過code以及code中的注釋看明白還是很困難的。所以先熟悉虛擬機的原理,再去看code,會針對性比較強。

2)分模塊閱讀code。hotspot包括的模塊確實太多,我們需要分成不同的模塊各個擊破。以GC為例,hotspot中的gc算法有很多種,parallel scavenge,cms,g1…等等,先弄懂這些算法的原理,再去看code會比較快。不要看二手資料,不要看翻譯資料,推薦R大的hllvm論壇以及周志明的深入java虛擬機,hotspot源碼閱讀這本書寫的也還可以。

繼承結(jié)構(gòu)

--java.lang.Object
 --java.io.InputStream

類定義

public abstract class InputStream implements Closeable

InputStream 被定為 public 且 abstract 的類,實現(xiàn)了Closeable接口。

Closeable 接口表示 InputStream 可以被close,接口定義如下:

public interface Closeable extends AutoCloseable {
  public void close() throws IOException;
}

主要屬性

private static final int MAX_SKIP_BUFFER_SIZE = 2048;

private static final int DEFAULT_BUFFER_SIZE = 8192;

private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
  • MAX_SKIP_BUFFER_SIZE 表示輸入流每次最多能跳過的字節(jié)數(shù)。
  • DEFAULT_BUFFER_SIZE 默認的緩沖大小。
  • MAX_BUFFER_SIZE 表示最大的緩沖數(shù)組大小,這里設(shè)置為 Integer.MAX_VALUE - 8 這里也是考慮到 JVM 能支持的大小,超過這個值就會導致 OutOfMemoryError。

主要方法

read方法

一共有三個 read 方法,其中有一個抽象的 read 方法,其余兩個 read 方法都會調(diào)用這個抽象方法,該方法用于從輸入流讀取下一個字節(jié),返回一個0到255范圍的值。如果已經(jīng)到達輸入流結(jié)尾處而導致無可讀字節(jié)則返回-1,同時,此方法為阻塞方法,解除阻塞的條件:

     1. 有可讀的字節(jié)。

     2. 檢測到已經(jīng)是輸入流的結(jié)尾了。

     3. 拋出異常。

主要看第三個 read 方法即可,它傳入的三個參數(shù),byte數(shù)組、偏移量和數(shù)組長度。該方法主要是從輸入流中讀取指定長度的字節(jié)數(shù)據(jù)到字節(jié)數(shù)組中,需要注意的是這里只是嘗試去讀取長度為 len 的數(shù)組,但真正讀取到的數(shù)組長度不一定為 len,返回值才是真正讀取到的長度。

  public abstract int read() throws IOException;

  public int read(byte b[]) throws IOException {
    return read(b, 0, b.length);
  }
  public int read(byte b[], int off, int len) throws IOException {
    if (b == null) {
      throw new NullPointerException();
    } else if (off < 0 || len < 0 || len > b.length - off) {
      throw new IndexOutOfBoundsException();
    } else if (len == 0) {
      return 0;
    }

    int c = read();
    if (c == -1) {
      return -1;
    }
    b[off] = (byte)c;

    int i = 1;
    try {
      for (; i < len ; i++) {
        c = read();
        if (c == -1) {
          break;
        }
        b[off + i] = (byte)c;
      }
    } catch (IOException ee) {
    }
    return i;
  }

看看它的邏輯,數(shù)組為null則拋空指針,偏移量和長度超過邊界也拋異常,長度為0則什么都不敢直接返回0。接著調(diào)用 read() 讀取一個字節(jié),如果為-1則說明結(jié)束,直接返回-1。否則繼續(xù)根據(jù)數(shù)組長度循環(huán)調(diào)用 read() 方法讀取字節(jié),并且填充到傳入的數(shù)組對象中,最后返回讀取的字節(jié)數(shù)。

readAllBytes方法

該方法從輸入流讀取所有剩余的字節(jié),在此過程是阻塞的,直到所有剩余字節(jié)都被讀取或到達流的結(jié)尾或發(fā)生異常。

邏輯是用一個 for 循環(huán)內(nèi)嵌一個 while 循環(huán),while 循環(huán)不斷調(diào)用 read 方法嘗試將 DEFAULT_BUFFER_SIZE 長度的字節(jié)數(shù)組填滿,一旦填滿則需要將數(shù)組容量擴容一倍,再將原字節(jié)數(shù)組復(fù)制到新數(shù)組中,然后再通過 while 循環(huán)繼續(xù)讀取,直到達到尾部才跳出 for 循環(huán),最后返回讀取到的所有字節(jié)數(shù)組。

  public byte[] readAllBytes() throws IOException {
    byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
    int capacity = buf.length;
    int nread = 0;
    int n;
    for (;;) {
      while ((n = read(buf, nread, capacity - nread)) > 0)
        nread += n;
      if (n < 0)
        break;
      if (capacity <= MAX_BUFFER_SIZE - capacity) {
        capacity = capacity << 1;
      } else {
        if (capacity == MAX_BUFFER_SIZE)
          throw new OutOfMemoryError("Required array size too large");
        capacity = MAX_BUFFER_SIZE;
      }
      buf = Arrays.copyOf(buf, capacity);
    }
    return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
  }

readNBytes方法

從輸入流中讀取指定長度的字節(jié),而且它能保證一定能讀取到指定的長度,它屬于阻塞方式,用一個 while 循環(huán)不斷調(diào)用 read 讀取字節(jié),直到讀取到指定長度才結(jié)束讀取。

  public int readNBytes(byte[] b, int off, int len) throws IOException {
    Objects.requireNonNull(b);
    if (off < 0 || len < 0 || len > b.length - off)
      throw new IndexOutOfBoundsException();
    int n = 0;
    while (n < len) {
      int count = read(b, off + n, len - n);
      if (count < 0)
        break;
      n += count;
    }
    return n;
  }

available方法

返回從該輸入流能進行非阻塞讀取的剩余字節(jié)數(shù),當調(diào)用 read 讀取的字節(jié)數(shù)一般會小于該值,有一些InputStream的子實現(xiàn)類會通過該方法返回流的剩余總字節(jié)數(shù),但有些并不會,所以使用時要注意點。

這里抽象類直接返回0,子類中重寫該方法。

public int available() throws IOException {
    return 0;
  }

skip方法

從輸入流中跳過指定個數(shù)字節(jié),返回值為真正跳過的個數(shù)。這里的實現(xiàn)是簡單通過不斷調(diào)用 read 方法來實現(xiàn)跳過邏輯,但這是較低效的,子類可用更高效的方式重寫此方法。

下面看看邏輯,最大的跳過長度不能超過 MAX_SKIP_BUFFER_SIZE ,并且用一個 while 循環(huán)調(diào)用 read 方法,如果遇到返回為-1,即已經(jīng)到達結(jié)尾了,則跳出循環(huán)??梢钥吹?skipBuffer 其實是沒有什么作用,直接讓其被 GC 即可,最后返回真正跳過的字節(jié)數(shù)。

  public long skip(long n) throws IOException {

    long remaining = n;
    int nr;

    if (n <= 0) {
      return 0;
    }

    int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
    byte[] skipBuffer = new byte[size];
    while (remaining > 0) {
      nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
      if (nr < 0) {
        break;
      }
      remaining -= nr;
    }

    return n - remaining;
  }

close方法

此方法用于關(guān)閉輸入流,并且釋放相關(guān)資源 。

public void close() throws IOException {}

transferTo方法

從輸入流中按順序讀取全部字節(jié)并且寫入到指定的輸出流中,返回值為轉(zhuǎn)移的字節(jié)數(shù)。轉(zhuǎn)移過程中可能會發(fā)生不確定次的阻塞,阻塞可能發(fā)生在 read 操作或 write 操作。

主要邏輯是用 while 循環(huán)不斷調(diào)用 read 方法操作讀取字節(jié),然后調(diào)用輸出流的 write 方法寫入,直到讀取返回-1,即達到結(jié)尾。最后返回轉(zhuǎn)移的字節(jié)數(shù)。

  public long transferTo(OutputStream out) throws IOException {
    Objects.requireNonNull(out, "out");
    long transferred = 0;
    byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
    int read;
    while ((read = this.read(buffer, 0, DEFAULT_BUFFER_SIZE)) >= 0) {
      out.write(buffer, 0, read);
      transferred += read;
    }
    return transferred;
  }

markSupported方法

是否支持 mark 和 reset 操作,這里直接返回 false,子類根據(jù)實際重寫該方法。

  public boolean markSupported() {
    return false;
  }

mark方法

標記輸入流當前位置,與之對應(yīng)的是 reset 方法,通過他們之間的組合能實現(xiàn)重復(fù)讀取操作。另外它會傳入 readlimit 參數(shù),它用于表示該輸入流中在執(zhí)行 mark 操作后最多可以讀 readlimit 個字節(jié)后才使 mark 的位置失效。

可以看到 InputStream 的 mark 方法是什么都不做的,子類中再具體實現(xiàn)。

public synchronized void mark(int readlimit) {}

reset方法

與 mark 方法對應(yīng),它可以重置輸入流的位置到上次被 mark 操作標識的位置。InputStream 的 reset 方法直接拋出一個 IOException,子類中根據(jù)實際情況實現(xiàn)。

  public synchronized void reset() throws IOException {
    throw new IOException("mark/reset not supported");
  }

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Springboot接口項目如何使用AOP記錄日志

    Springboot接口項目如何使用AOP記錄日志

    這篇文章主要介紹了Springboot接口項目如何使用AOP記錄日志,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • 記一次集成swagger2(Knife4j)在線文檔提示:Knude4j文檔請求異常的解決辦法

    記一次集成swagger2(Knife4j)在線文檔提示:Knude4j文檔請求異常的解決辦法

    Knife4j是一個集Swagger2 和 OpenAPI3為一體的增強解決方案,下面這篇文章主要給大家介紹了關(guān)于一次集成swagger2(Knife4j)在線文檔提示:Knude4j文檔請求異常的解決辦法,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-02-02
  • Java中泛型通配符的使用方法示例

    Java中泛型通配符的使用方法示例

    這篇文章主要介紹了Java中泛型通配符的使用方法,結(jié)合實例形式分析了java中泛型通配符的功能、語法及在泛型類創(chuàng)建泛型對象中的使用方法,需要的朋友可以參考下
    2019-08-08
  • Spring Boot 編寫Servlet、Filter、Listener、Interceptor的方法

    Spring Boot 編寫Servlet、Filter、Listener、Interceptor的方法

    這篇文章給大家介紹了spring-boot中如何定義過濾器、監(jiān)聽器和攔截器,對Spring Boot 編寫Servlet、Filter、Listener、Interceptor的相關(guān)知識感興趣的朋友一起看看吧
    2017-07-07
  • Java判斷用戶名和密碼是否符合要求過程詳解

    Java判斷用戶名和密碼是否符合要求過程詳解

    這篇文章主要介紹了Java判斷用戶名和密碼過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-02-02
  • 解決springboot整合cxf啟動報錯,原因是版本問題

    解決springboot整合cxf啟動報錯,原因是版本問題

    這篇文章主要介紹了解決springboot整合cxf啟動報錯,原因是版本問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • SpringBoot3集成Kafka的方法詳解

    SpringBoot3集成Kafka的方法詳解

    Kafka是一個開源的分布式事件流平臺,常被用于高性能數(shù)據(jù)管道、流分析、數(shù)據(jù)集成和關(guān)鍵任務(wù)應(yīng)用,下面我們就來看看SpringBoot3是如何集成Kafka的吧
    2023-08-08
  • java實現(xiàn)百度坐標的摩卡托坐標與火星坐標轉(zhuǎn)換的示例

    java實現(xiàn)百度坐標的摩卡托坐標與火星坐標轉(zhuǎn)換的示例

    這篇文章主要介紹了java實現(xiàn)百度坐標的摩卡托坐標與火星坐標轉(zhuǎn)換的示例,需要的朋友可以參考下
    2014-03-03
  • springcloud feign傳輸List的坑及解決

    springcloud feign傳輸List的坑及解決

    這篇文章主要介紹了springcloud feign傳輸List的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java線性表的順序表示及實現(xiàn)

    Java線性表的順序表示及實現(xiàn)

    這篇文章主要介紹了Java線性表的順序表示及實現(xiàn),順序表是在計算機內(nèi)存中以數(shù)組的形式保存的線性表,線性表的順序存儲是指用一組地址連續(xù)的存儲單元依次存儲線性表中的各個元素、使得線性表中在邏輯結(jié)構(gòu)上相鄰的數(shù)據(jù)元素存儲在相鄰的物理存儲單元中
    2022-07-07

最新評論

苗栗县| 达尔| 巍山| 顺义区| 晋宁县| 虎林市| 冕宁县| 霸州市| 清河县| 葵青区| 巴彦淖尔市| 昌吉市| 碌曲县| 孟连| 晴隆县| 子长县| 海南省| 澄江县| 丰宁| 桑植县| 涟水县| 湟中县| 恩平市| 大连市| 仁怀市| 名山县| 根河市| 自贡市| 岢岚县| 汉川市| 邵阳县| 宁蒗| 堆龙德庆县| 枣庄市| 吴忠市| 罗平县| 额济纳旗| 普宁市| 敖汉旗| 华容县| 丹棱县|