Java的IO是一個大知識點,
如果把它的知識點拆開來說的話估計能說一個星期,關於IO的體系可以看看下面這張圖,
(圖片是網上找的,侵刪)
接下來我們從一段代碼開始聊吧,先看看下面這段代碼
public class Test {
public static void main(String[] args) throws Exception {
File file = new File("text.txt");
if(!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] b = new byte[1024];
bos.write(b);
bos.flush();
}
}
代碼中構造了一個緩衝流,然後往流裏寫入一個KB長度的數據,最後調用 flush()方法。
這是很簡單的一段代碼,最終的輸出結果是會生成一個 1KB的 text.text文件。
但如果我們把最後一行註釋掉的話,
//bos.flush();
最終生成的 text.text大小會變成0.
這個結果是很顯然的,不過如果我們把 flush()換成 close()的話,結果是不是還會是 0呢?
關於 flush
flush()這個東西,其實在很久以前的網絡傳輸中就有了,
那個時候爲了效率,服務器和客戶端傳輸數據的時候不會每產生一段數據就傳一段數據,
而是會建一個緩衝區,在緩衝區滿之後再往客戶端傳輸數據,
有時候會有這樣的問題,當數據不足以填充緩衝區,而又需要往客戶端傳數據,
爲了解決這個問題,就有了 flush的概念,將緩衝區的數據強迫發送。
回到上面的問題,如果把 flush換成 close是否可行呢,
答案是可以的。
如果看源碼就知道 BufferedOutputStream的繼承關係,
public class BufferOutputStream extends FilterOutputStream
BufferedOutputStream沒有實現 close()方法,所以會直接調用 FilterOutputStream的 close(),
而 FilterOutputStream的 close()方法會調用 flush()來輸出緩衝區數據。
實際開發中關於IO操作的,都強調最後要調用 close()方法,
上面的例子就是其中一個原因了。
關於Enum的再次理解
問:enum 算不算基本數據類型
答:不算,enum是引用類型。
Java中的基本數據類型只有8種,分別是
byte、short、int、long、float、double、char、boolean
在 Java5之後新增的 Enum屬於引用類型,跟 String一樣也是屬於類。
好奇的同學可能有疑問,既然說 enum是引用類型,爲何在使用的時候沒有見到類呢?
enum的使用場景
我們先來看一個簡單的enum使用場景,
public class DayDemo {
public enum Day {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY
}
public static void main(String[] args) {
}
}
這裏面只定義了一個枚舉類型 Day,
通過枚舉定義了週一到週四四種類型,後續我們使用的時候就可以直接用 Day.MONDAY 這樣的方式來使用枚舉值了。
爲什麼說枚舉是類
在這代碼裏沒有聲明類,也沒用其他的引用,
那麼來看看編譯後的結果
$ ls
'DayDemo$Day.class' DayDemo.class DayDemo.java
可以看到多了一個叫 DayDemo$Day.class的類出來,
從 class文件可以看出, 枚舉 Day編譯成了一個類,從這裏可以斷定雖然我們沒有定義這個類,
但是編譯器會把枚舉作爲類進行編譯,從某種角度上來說 enum是一種語法糖,
現在來看一下 class文件的構造,
public final class DayDemo$Day extends java.lang.Enum<DayDemo$Day> {
public static final DayDemo$Day MONDAY;
public static final DayDemo$Day TUESDAY;
public static final DayDemo$Day WEDNESDAY;
public static final DayDemo$Day THURSDAY;
public static DayDemo$Day[] values();
Code:
0: getstatic #1 // Field $VALUES:[LDayDemo$Day;
3: invokevirtual #2 // Method "[LDayDemo$Day;".clone:()Ljava/lang/Object;
6: checkcast #3 // class "[LDayDemo$Day;"
9: areturn
public static DayDemo$Day valueOf(java.lang.String);
Code:
0: ldc #4 // class DayDemo$Day
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class DayDemo$Day
9: areturn
static {};
Code:
0: new #4 // class DayDemo$Day
3: dup
4: ldc #7 // String MONDAY
6: iconst_0
7: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
10: putstatic #9 // Field MONDAY:LDayDemo$Day;
13: new #4 // class DayDemo$Day
16: dup
17: ldc #10 // String TUESDAY
19: iconst_1
20: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
23: putstatic #11 // Field TUESDAY:LDayDemo$Day;
26: new #4 // class DayDemo$Day
29: dup
30: ldc #12 // String WEDNESDAY
32: iconst_2
33: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
36: putstatic #13 // Field WEDNESDAY:LDayDemo$Day;
39: new #4 // class DayDemo$Day
42: dup
43: ldc #14 // String THURSDAY
45: iconst_3
46: invokespecial #8 // Method "<init>":(Ljava/lang/String;I)V
49: putstatic #15 // Field THURSDAY:LDayDemo$Day;
52: iconst_4
53: anewarray #4 // class DayDemo$Day
56: dup
57: iconst_0
58: getstatic #9 // Field MONDAY:LDayDemo$Day;
61: aastore
62: dup
63: iconst_1
64: getstatic #11 // Field TUESDAY:LDayDemo$Day;
67: aastore
68: dup
69: iconst_2
70: getstatic #13 // Field WEDNESDAY:LDayDemo$Day;
73: aastore
74: dup
75: iconst_3
76: getstatic #15 // Field THURSDAY:LDayDemo$Day;
79: aastore
80: putstatic #1 // Field $VALUES:[LDayDemo$Day;
83: return
}
如果上面的代碼不夠簡潔易懂的話可以看看下面翻譯後的代碼,
這隻翻譯 static代碼段,其他的像 values和 valueOf都比較簡單,
static
{
//實例化枚舉實例
MONDAY = new Day("MONDAY", 0);
TUESDAY = new Day("TUESDAY", 1);
WEDNESDAY = new Day("WEDNESDAY", 2);
THURSDAY = new Day("THURSDAY", 3);
$VALUES = (new Day[] {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY
});
}
總結
把這段代碼和上面反編譯的結果一起看的話就可以明白,
枚舉類型在編譯後會作爲一個類生成,
編譯器會幫我們插入 values和 valueOf 兩個方法,
同時生成 final的常量,
在生成的靜態代碼段裏會實例化好對應的枚舉實例,
換句話說,我們所定義的每個枚舉類,最終都會在它裏面生成對應的靜態常量,而常量的值就是我們所定義的值的String串。
Java中如何操作超大數