Java IO的flush

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中如何操作超大數

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章