枚举是如何实现的?(枚举的线程安全性及序列化问题)
生活随笔
收集整理的這篇文章主要介紹了
枚举是如何实现的?(枚举的线程安全性及序列化问题)
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
?
枚舉是如何實現(xiàn)的?(枚舉的線程安全性及序列化問題)- 枚舉是如何保證線程安全的
- 舉例源碼
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關(guān)鍵字告訴我們,這個類也是不能被繼承的。當(dāng)我們使用enmu來定義一個枚舉類型的時候,編譯器會自動幫我們創(chuàng)建一個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類型的屬性會在類被加載之后被初始化。當(dāng)一個Java類第一次被真正使用到的時候靜態(tài)資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創(chuàng)建一個enum類型是線程安全的。
- 舉例源碼
- 為什么用枚舉實現(xiàn)的單例是最好的方式
- 1. 枚舉寫法簡單
1 public enum EasySingleton{ 2 INSTANCE; 3 } - 2. 枚舉自己處理序列化
- 我們知道,以前的所有的單例模式都有一個比較大的問題,就是一旦實現(xiàn)了Serializable接口之后,就不再是單例得了,因為,每次調(diào)用 readObject()方法返回的都是一個新創(chuàng)建出來的對象,有一種解決辦法就是使用readResolve()方法來避免此事發(fā)生。但是,為了保證枚舉類型像Java規(guī)范中所說的那樣,每一個枚舉類型極其定義的枚舉變量在JVM中都是唯一的,在枚舉類型的序列化和反序列化上,Java做了特殊的規(guī)定。大概意思就是說,在序列化的時候Java僅僅是將枚舉對象的name屬性輸出到結(jié)果中,反序列化的時候則是通過java.lang.Enum的valueOf方法來根據(jù)名字查找枚舉對象。同時,編譯器是不允許任何對這種序列化機制的定制的,因此禁用了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 } - 從代碼中可以看到,代碼會嘗試從調(diào)用enumType這個Class對象的enumConstantDirectory()方法返回的map中獲取名字為name的枚舉對象,如果不存在就會拋出異常。再進一步跟到enumConstantDirectory()方法,就會發(fā)現(xiàn)到最后會以反射的方式調(diào)用enumType這個類型的values()靜態(tài)方法,也就是上面我們看到的編譯器為我們創(chuàng)建的那個方法,然后用返回結(jié)果填充enumType這個Class對象中的enumConstantDirectory屬性。所以,JVM對序列化有保證。
- 3.枚舉實例創(chuàng)建是thread-safe(線程安全的)
- 當(dāng)一個Java類第一次被真正使用到的時候靜態(tài)資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創(chuàng)建一個enum類型是線程安全的。
- 1. 枚舉寫法簡單
- 參考http://www.hollischuang.com/archives/197
?
轉(zhuǎn)載于:https://www.cnblogs.com/More-World/p/9563394.html
總結(jié)
以上是生活随笔為你收集整理的枚举是如何实现的?(枚举的线程安全性及序列化问题)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Centos升级Python2.7.12
- 下一篇: docker remote api未授权