Java 枚舉與泛型

Java 枚舉

之前寫過的文檔:https://blog.csdn.net/Roobert_Chao/article/details/78637972

枚舉對象的常用方法

枚舉對象的常用方法

Java 枚舉的本質理解

Java 枚舉的本質原理是通過普通類來實現的,經過編譯器的加工處理(編譯後生成的類是final class 類,且繼承了 Enum 類),枚舉值加工成爲類的靜態常量屬性,其屬性在類加載的靜態代碼塊中被初始化實例賦值。
在這裏插入圖片描述
查看字節碼(.class)文件

  1. 命令行的方式:javap -c 文件所在目錄。
    在這裏插入圖片描述
  2. 使用插件工具 【IDEA】,添加插件 jclasslib bytecode viewer。
  3. 下載本地工具【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
}

枚舉類與常量類

在使用枚舉類的時候,發現枚舉常量+枚舉值,和常量類中常量賦值是一樣的。那麼爲什麼會出現枚舉類呢 ???

  1. 枚舉相對於常量類來說更加的簡單,可以不定義枚舉值。而常量類中的每個常量必須要手動添加值。
  2. 枚舉類自動具備內置方法(如 values 方法可以獲得所有值的集合類遍歷,ordinal 方法可以獲得排序值,compareTo 方法可以基於 ordinal 比較)。常量類不具備這些方法。
  3. 枚舉類編譯後生成了 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 泛型是通過 擦除來實現的

  1. 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 。

  1. 擦除前的類型檢查是針對引用的,用這個引用調用泛型方法就會對這個引用調用的方法進行類型檢測而無關真正引用的對象。泛型中參數化類型不支持繼承關係。且不能是基本類型。
    在這裏插入圖片描述
  2. 泛型無法進行具體泛型參數類型的運行時檢查。而且不能拋出,也不能捕獲泛型類對象。
arrayList instanceof ArrayList<String> 是非法的。
arrayList instanceof ArrayList<?> 僅這種方式。
  1. Java 的泛型數組不能採用具體的泛型類型進行初始化。只能通過通配符的形式。
建議:
List<?>[] list = new ListArray<?>[10];

在這裏插入圖片描述

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