枚举是如何实现的?(枚举的线程安全性及序列化问题)
生活随笔
收集整理的這篇文章主要介紹了
枚举是如何实现的?(枚举的线程安全性及序列化问题)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?
枚舉是如何實現的?(枚舉的線程安全性及序列化問題)- 枚舉是如何保證線程安全的
- 舉例源碼
1 public enum t { 2 SPRING,SUMMER,AUTUMN,WINTER; 3 } - 反編譯源碼
1 public final class T extends Enum 2 { 3 private T(String s, int i) 4 { 5 super(s, i); 6 } 7 public static T[] values() 8 { 9 T at[]; 10 int i; 11 T at1[]; 12 System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0, i); 13 return at1; 14 } 15 public static T valueOf(String s) 16 { 17 return (T)Enum.valueOf(demo/T, s); 18 } 19 public static final T SPRING; 20 public static final T SUMMER; 21 public static final T AUTUMN; 22 public static final T WINTER; 23 private static final T ENUM$VALUES[]; 24 static 25 { 26 SPRING = new T("SPRING", 0); 27 SUMMER = new T("SUMMER", 1); 28 AUTUMN = new T("AUTUMN", 2); 29 WINTER = new T("WINTER", 3); 30 ENUM$VALUES = (new T[] { 31 SPRING, SUMMER, AUTUMN, WINTER 32 }); 33 } 34 } - 通過反編譯后代碼我們可以看到,public final class T extends Enum,說明,該類是繼承了Enum類的,同時final關鍵字告訴我們,這個類也是不能被繼承的。當我們使用enmu來定義一個枚舉類型的時候,編譯器會自動幫我們創建一個final類型的類繼承Enum類,所以枚舉類型不能被繼承,我們看到這個類中有幾個屬性和方法。
- 我們可以看到:
1 public static final T SPRING; 2 public static final T SUMMER; 3 public static final T AUTUMN; 4 public static final T WINTER; 5 private static final T ENUM$VALUES[]; 6 static 7 { 8 SPRING = new T("SPRING", 0); 9 SUMMER = new T("SUMMER", 1); 10 AUTUMN = new T("AUTUMN", 2); 11 WINTER = new T("WINTER", 3); 12 ENUM$VALUES = (new T[] { 13 SPRING, SUMMER, AUTUMN, WINTER 14 }); 15 } - 都是static類型的,因為static類型的屬性會在類被加載之后被初始化。當一個Java類第一次被真正使用到的時候靜態資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創建一個enum類型是線程安全的。
- 舉例源碼
- 為什么用枚舉實現的單例是最好的方式
- 1. 枚舉寫法簡單
1 public enum EasySingleton{ 2 INSTANCE; 3 } - 2. 枚舉自己處理序列化
- 我們知道,以前的所有的單例模式都有一個比較大的問題,就是一旦實現了Serializable接口之后,就不再是單例得了,因為,每次調用 readObject()方法返回的都是一個新創建出來的對象,有一種解決辦法就是使用readResolve()方法來避免此事發生。但是,為了保證枚舉類型像Java規范中所說的那樣,每一個枚舉類型極其定義的枚舉變量在JVM中都是唯一的,在枚舉類型的序列化和反序列化上,Java做了特殊的規定。大概意思就是說,在序列化的時候Java僅僅是將枚舉對象的name屬性輸出到結果中,反序列化的時候則是通過java.lang.Enum的valueOf方法來根據名字查找枚舉對象。同時,編譯器是不允許任何對這種序列化機制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。
- 我們看一下這個valueOf方法:
1 public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) { 2 T result = enumType.enumConstantDirectory().get(name); 3 if (result != null) 4 return result; 5 if (name == null) 6 throw new NullPointerException("Name is null"); 7 throw new IllegalArgumentException( 8 "No enum const " + enumType +"." + name); 9 } - 從代碼中可以看到,代碼會嘗試從調用enumType這個Class對象的enumConstantDirectory()方法返回的map中獲取名字為name的枚舉對象,如果不存在就會拋出異常。再進一步跟到enumConstantDirectory()方法,就會發現到最后會以反射的方式調用enumType這個類型的values()靜態方法,也就是上面我們看到的編譯器為我們創建的那個方法,然后用返回結果填充enumType這個Class對象中的enumConstantDirectory屬性。所以,JVM對序列化有保證。
- 3.枚舉實例創建是thread-safe(線程安全的)
- 當一個Java類第一次被真正使用到的時候靜態資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創建一個enum類型是線程安全的。
- 1. 枚舉寫法簡單
- 參考http://www.hollischuang.com/archives/197
?
轉載于:https://www.cnblogs.com/More-World/p/9563394.html
總結
以上是生活随笔為你收集整理的枚举是如何实现的?(枚举的线程安全性及序列化问题)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Centos升级Python2.7.12
- 下一篇: docker remote api未授权