Java 枚舉
之前寫過的文檔:https://blog.csdn.net/Roobert_Chao/article/details/78637972
枚舉對象的常用方法
Java 枚舉的本質理解
Java 枚舉的本質原理是通過普通類來實現的,經過編譯器的加工處理(編譯後生成的類是final class 類,且繼承了 Enum 類
),枚舉值加工成爲類的靜態常量屬性,其屬性在類加載的靜態代碼塊中被初始化實例賦值。
查看字節碼(.class)文件
- 命令行的方式:javap -c 文件所在目錄。
- 使用插件工具 【IDEA】,添加插件 jclasslib bytecode viewer。
- 下載本地工具【JBE - Java Bytecode Editor】: http://set.ee/jbe/
上述枚舉類型的編譯後的代碼如下:
public final class cn.chao.override.equals.ColorEnum extends java.lang.Enum<cn.chao.override.equals.ColorEnum> { // 類變成了 final class
// 三種靜態常量
public static final cn.chao.override.equals.ColorEnum RED;
public static final cn.chao.override.equals.ColorEnum BLUE;
public static final cn.chao.override.equals.ColorEnum GREEN;
// 自定義字符串類型的屬性
public java.lang.String color;
static {};
Code:
0: new #1 // class cn/chao/override/equals/ColorEnum
3: dup
4: ldc #16 // String RED
6: iconst_0
7: ldc #17 // String red
9: invokespecial #19 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
12: putstatic #23 // Field RED:Lcn/chao/override/equals/ColorEnum;
15: new #1 // class cn/chao/override/equals/ColorEnum
18: dup
19: ldc #25 // String BLUE
21: iconst_1
22: ldc #26 // String blue
24: invokespecial #19 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
27: putstatic #28 // Field BLUE:Lcn/chao/override/equals/ColorEnum;
30: new #1 // class cn/chao/override/equals/ColorEnum
33: dup
34: ldc #30 // String GREEN
36: iconst_2
37: ldc #31 // String green
39: invokespecial #19 // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
42: putstatic #33 // Field GREEN:Lcn/chao/override/equals/ColorEnum;
45: iconst_3
46: anewarray #1 // class cn/chao/override/equals/ColorEnum
49: dup
50: iconst_0
51: getstatic #23 // Field RED:Lcn/chao/override/equals/ColorEnum;
54: aastore
55: dup
56: iconst_1
57: getstatic #28 // Field BLUE:Lcn/chao/override/equals/ColorEnum;
60: aastore
61: dup
62: iconst_2
63: getstatic #33 // Field GREEN:Lcn/chao/override/equals/ColorEnum;
66: aastore
67: putstatic #35 // Field ENUM$VALUES:[Lcn/chao/override/equals/ColorEnum;
70: return
public static cn.chao.override.equals.ColorEnum[] values();
Code:
0: getstatic #35 // Field ENUM$VALUES:[Lcn/chao/override/equals/ColorEnum;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1 // class cn/chao/override/equals/ColorEnum
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #47 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
20: aload_2
21: areturn
public static cn.chao.override.equals.ColorEnum valueOf(java.lang.String);
Code:
0: ldc #1 // class cn/chao/override/equals/ColorEnum
2: aload_0
3: invokestatic #55 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #1 // class cn/chao/override/equals/ColorEnum
9: areturn
}
枚舉類與常量類
在使用枚舉類的時候,發現枚舉常量+枚舉值,和常量類中常量賦值是一樣的。那麼爲什麼會出現枚舉類呢 ???
- 枚舉相對於常量類來說更加的簡單,可以不定義枚舉值。而常量類中的每個常量必須要手動添加值。
- 枚舉類自動具備內置方法(如 values 方法可以獲得所有值的集合類遍歷,ordinal 方法可以獲得排序值,compareTo 方法可以基於 ordinal 比較)。常量類不具備這些方法。
枚舉類編譯後生成了 final class 類,且繼承了 Enum 類(Java 單繼承機制),所以枚舉類不能夠繼承,但是定義的枚舉類可以通過 implement 實現其他接口。
Java 枚舉與線程安全
1. Java 類加載和初始化是 Java 虛擬機(JVM )保證線程安全。
2. static 的常量屬性和代碼塊都是在類加載時初始化完成的。
Java 枚舉類編譯後的代碼,實質上是一個 final 類,枚舉常量初始化都是在 static 代碼塊中進行的,自然就 JVM 保證線程安全。
Java 泛型(參數化類型)
之前寫過的文檔:https://blog.csdn.net/Roobert_Chao/article/details/78634340
1. 參數化類型,泛型類、泛型接口、泛型方法
。
2. 提高了代碼的重用率,避免在運行時出現 ClassCastException。
Java 泛型是通過 擦除
來實現的
- Java 泛型是通過擦除來實現的,所以編譯後的任何具體泛型類型都被擦除了。
(替換爲非泛型上邊界,沒有上邊界,則上邊界就是 Object 類型。)
通過反射增加字符串
觀察如下的代碼:輸出結果爲
public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(1);
list.getClass().getMethod("add", Object.class).invoke(list, "abc");
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
由於在程序中定義的 ArrayList 泛型類型實例化爲 Integer 的對象,如果直接調用 add 方法則只能存儲整型數據,不過當我們利用反射調用 add 方法時,就可以存儲字符串。因爲 Integer 泛型實例在編譯之後被擦除了,只保留了原始類型 Object 。
- 擦除前的類型檢查是
針對引用的
,用這個引用調用泛型方法就會對這個引用調用的方法進行類型檢測而無關真正引用的對象。泛型中參數化類型不支持繼承關係。且不能是基本類型。
- 泛型無法進行具體泛型參數類型的運行時檢查。而且不能拋出,也不能捕獲泛型類對象。
arrayList instanceof ArrayList<String> 是非法的。
arrayList instanceof ArrayList<?> 僅這種方式。
- Java 的泛型數組不能採用具體的泛型類型進行初始化。只能通過通配符的形式。
建議:
List<?>[] list = new ListArray<?>[10];