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;) {
//使用流
}