激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 通過JDK源碼學習InputStream詳解

通過JDK源碼學習InputStream詳解

2021-02-01 11:44汪洋之舟---seaboat Java教程

InputStream抽象類是所有字節(jié)輸入流的類的超類。這篇文章主要給大家介紹了關于通過JDK源碼學習InputStream的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編

概況

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

如何閱讀JDK源碼。

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

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

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

繼承結構

?
1
2
--java.lang.Object
 --java.io.InputStream

類定義

?
1
public abstract class InputStream implements Closeable

InputStream 被定為 public 且 abstract 的類,實現了Closeable接口。

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

?
1
2
3
public interface Closeable extends AutoCloseable {
  public void close() throws IOException;
}

主要屬性

?
1
2
3
4
5
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é)數。
  • DEFAULT_BUFFER_SIZE 默認的緩沖大小。
  • MAX_BUFFER_SIZE 表示最大的緩沖數組大小,這里設置為 Integer.MAX_VALUE - 8 這里也是考慮到 JVM 能支持的大小,超過這個值就會導致 OutOfMemoryError。

主要方法

read方法

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

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

     2. 檢測到已經是輸入流的結尾了。

     3. 拋出異常。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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;
}

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

readAllBytes方法

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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)不斷調用 read 讀取字節(jié),直到讀取到指定長度才結束讀取。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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é)數,當調用 read 讀取的字節(jié)數一般會小于該值,有一些InputStream的子實現類會通過該方法返回流的剩余總字節(jié)數,但有些并不會,所以使用時要注意點。

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

?
1
2
3
public int available() throws IOException {
    return 0;
  }

skip方法

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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方法

此方法用于關閉輸入流,并且釋放相關資源 。

?
1
public void close() throws IOException {}

transferTo方法

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

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

?
1
2
3
4
5
6
7
8
9
10
11
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,子類根據實際重寫該方法。

?
1
2
3
public boolean markSupported() {
  return false;
}

mark方法

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

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

?
1
public synchronized void mark(int readlimit) {}

reset方法

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

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

總結

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

原文鏈接:http://blog.csdn.net/wangyangzhizhou/article/details/78465531

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 99久久久精品 | 中文字幕亚洲视频 | 欧美一级高潮 | 91九色网| 精品一区在线视频 | 国产精品久久久久久久久久久久午夜 | 男女无遮挡羞羞视频 | 黄色网址免费在线播放 | 一级免费 | 女18一级大黄毛片免费女人 | 国产精品91在线 | 精品国产乱码久久久久久丨区2区 | 久久国产精品久久精品国产演员表 | 成人久久久精品乱码一区二区三区 | 精品亚洲在线 | 精品亚洲va在线va天堂资源站 | 欧美一级爱操视频 | 国产一级在线看 | 爱操视频 | 宅男噜噜噜66国产在线观看 | 91免费在线视频 | 久久凹凸 | 一区二区三区四区视频在线观看 | 久久久久久免费 | 久久国产亚洲视频 | av在线免费网 | 国产精品av久久久久久久久久 | 欧美一级黄色录像片 | 91看电影 | 国产一级小视频 | 特级黄色影院 | 日本教室三级在线看 | 在线视频观看一区二区 | 日韩黄色影视 | 日韩激情 | 久久国产精品久久久久久电车 | 国产91精品久久久 | 精品一区二区亚洲 | 亚洲国产精品一区二区三区 | 国产午夜免费福利 | 日本一区二区在线 |