1.1、java.io(精讀部分)

java源碼閱讀專欄說明

1、源碼閱讀不包括異常和錯誤

2、一篇或者幾篇文章是說不清楚的。光看博客也不會有多大的進步,或者說過段時間就會忘記。java源碼閱讀專欄旨在根據 代碼 和文檔的基礎上來記錄一些我自己的感受和想法。當然,我也會汲取一些其他人的收穫。並將它們傳播。

3、最主要的是瞭解這些源碼的編程風格和一些規範,具體的一些說明,這個接口或者類是幹什麼的?可能也會涉及到

接下來開始,第一個包的瞭解:

java.io包是繼承和接口運用得最棒例子了(這話是聽別人說的,可從這個包的結構,可以看出確實很流暢。),我也是初次來閱讀它,確實,io在平時用的也很多。而且io裏面的東西也是其他部分的一些基礎。所以我準備先來看看這個包的一些東西。

概覽圖

在這裏插入圖片描述

字節流可以處理所有類型數據,如:圖片,MP3,AVI視頻文件,而字符流只能處理字符數據。只有是處理純文本數據,就要優先考慮使用字符流,除此之外都用字節流。

Interfaces部分

在這裏插入圖片描述
更多其他,請參考我的另一篇博客:Java基礎總結!精華版!
的第19點。

接口實際上是定義了一種規範,所有實現了相應接口的類,或者接口,都得去安照它規範去做一些開發。

Closeable

Closeable使用,其中有一個方法,close(),這個接口還有一個父接口AutoCloseable,autocloseable來自java.lang
在這裏插入圖片描述
在這裏插入圖片描述
可以看到close方法拋出的是io異常,查看後發現,InputStream,OutputStream都實現了Closeable接口。

說明,Closeable就是用來定義關閉流的一個“規範”(接口就是一種規範)。

DataInput && DataOutput

DataInput提供從二進制流讀取字節,並從其中重建任何Java原語類型的數據。 同時還提供根據 UTF-8 修改版格式的數據重構 String 的工具。

DataOutput和它相反,提供將數據從任何Java基本類型轉換爲一系列字節,並將這些字節寫入二進制流。同時還提供了一個將 String 轉換成 UTF-8 修改版格式並寫入所得到的系列字節的工具。

這個兩個接口中有很多的方法,具體的我也不照搬文檔了,但我發現,所有的接口,都是沒有訪問修飾符的,即 public…,因爲接口中默認的,所以的方法都是公有的,且沒有方法體的。

平時的開發寫代碼的時候,可以模仿。還有每一個方法都有對應的註釋,註釋也符合java的一些規範,比如最起碼的,方法描述,參數介紹,返回值…

ObjectInput &ObjectOutput

在這裏插入圖片描述
在這裏插入圖片描述
如上,ObjectInput和ObjectOutput繼承了兩個接口。

在ObjectInput和ObjectOutput中的方法,都用了訪問修飾符。作者和版本如下。。作者是佚名,jdk中有很多的代碼作者,都是佚名。
在這裏插入圖片描述

Serializable

Serializable接口,只是一個標記接口,就是說,它沒有方法和屬性。
更多關於序列化,請查看我的另一篇博客:
深入【Java】底層細節知識點 的第十七點

java.io中Externalizable接口就繼承了serializable接口

Flushable

Flushable 是可刷新數據的目標地。調用 flush 方法將所有已緩衝輸出寫入底層流。

該接口定義了一個我們常用的方法,flush(),通過將所有已緩衝輸出寫入底層流來刷新此流。

還有其他的一些接口,比如: ObjectInputValidation, FileFilter ,FilenameFilter , ObjectStreamConstants


Classes部分

首先,輸入流,輸出流是相對內存而言的。內存在一定程度上可以理解爲,程序,即你寫的代碼;但是代碼運行其實是在內存中的。這一塊,jvm會進行進一步研究。

字節流:
輸入流:相對於內存,向內存中寫入;
輸出流:相對於內存,從內存往外讀;

字符流:
Reader(字符輸入流),我是這樣理解的,從文件(文本)中讀取一些字符,然讀取到內存中;
Writer(字符輸出流),從內存中拿到東西寫到文件中;

類這部分,我們就按照這幅圖來研究,
在這裏插入圖片描述

InputStream

此抽象類是表示字節輸入流的所有類的超類。
在這裏插入圖片描述
InputStream 是一個抽象類。
類中,有兩個非抽象的方法:

public int read(byte b[]) throws IOException {
	return read(b, 0, b.length);
}
/**
這兩個方法本身沒有什麼特別,特別之處,在於,沒有直接用下面的方法,
而是包了一層(上面的方法)

這種,大家也都清楚,兩個方法,方法名相同,參數個數或者類型不同,
叫做方法重載。

重載的好處:便於記憶篩選,體現了java的多態
*/
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;
}

接下來,看我的一個例子,這樣寫起來,確實清晰明瞭。

public void test(int i){
	//做些什麼
}

public void test(int[] intArr){
	//像這樣做點什麼
	test(intArr[i]);
}

public void test(int[][] intArr){
	test(intArr[i][j]);
}

再比如我項目中的一個例子:

 byte[] data = null;
 try {
      InputStream in = bi2is(bi);
      //數據在底層傳輸的時候,是要拆分成包,幀的
      //在進行網絡操作時往往出錯,因爲你調用available()方法時,對發發送的數據可能還沒有到達,你得到的count是0。
      int count = 0;
      while (count == 0){
        count = in.available()
      }
      data = new byte[count];
      in.read(data);
      in.close();
      // 對字節數組Base64編碼
      BASE64Encoder encoder = new BASE64Encoder();
      String s = encoder.encode(data);// 返回Base64編碼過的字節數組字符串
//            s=s.substring(0,10);
      return s;
  } catch (IOException e) {
      e.printStackTrace();
  }
  return "";

我們只需關注 in.read(data);這行,來理解輸入流中的read方法。
in中存了一些東西,我們用read方法,讀出來,然後做一些處理
在這裏插入圖片描述

OutputStream

對稱的總是美好的~

此抽象類是表示輸出字節流的所有類的超類。輸出流接受輸出字節並將這些字節發送到某個接收器。

Reader

Reader是抽象類並且有倆抽象方法(read(char[], int, int) 和 close()),所以,子類都必須重寫這倆方法,但一般的子類都會自定義這倆方法。

java中的字符是Unicode編碼的,是雙字節的。InputStream是用來處理字節的,在處理字符文本時很不方便。Java爲字符文本的輸入提供了專門的一套類Reader。Reader類是字符輸入流的抽象類,所有字符輸入流的實現都是它的子類。

現在是不是有一個困惑:字節和字符的區別?

字節(Byte)是一種計量單位,表示數據量多少,它是計算機信息技術用於計量存儲容量的一種計量單位。

字符是指計算機中使用的文字和符號,比如1、2、3、A、B、C、~!·#¥%……—*()-+、等等。

兩者不是一個位面的東西。沒有可比性。

另外:不同編碼裏,字符和字節的對應關係不同:

  • ASCII碼中:一個英文字母(不分大小寫)佔一個字節的空間,一箇中文漢字佔兩個字節的空間。
    一個二進制數字序列,在計算機中作爲一個數字單元,一般爲8位二進制數,換算爲十進制。最小值0,最大值255。

  • UTF-8編碼中:一個英文字符等於一個字節,一箇中文(含繁體)等於三個字節。

  • Unicode編碼中:一個英文字符等於兩個字節,一箇中文(含繁體)等於兩個字節。

    符號:英文標點佔一個字節;中文標點佔兩個字節。
    舉例:英文句號“.”佔1個字節的大小;中文句號“。”佔2個字節的大小。

  • UTF-16編碼中:一個英文字母字符或一個漢字字符存儲都需要2個字節(Unicode擴展區的一些漢字存儲需要4個字節)。

  • UTF-32編碼中:世界上任何字符的存儲都需要4個字節。

Writer

寫入字符流的抽象類。子類必須實現的方法僅有 write(char[], int, int)、flush() 和 close()

流的使用,結束以後,一定要關閉;
1、jdk1.7之前

InputStream is = null;
try {
    //使用流
}finally {
    if(is!=null){
        is.close();//拋出異常
    }
}

2、
try-with-resource(jdk1.7以後)

try(InputStream is = null;) {
    //使用流
}
發佈了65 篇原創文章 · 獲贊 271 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章