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串。