亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

深度分析Java的枚舉類型:枚舉的線程安全性及序列化問題

2019-11-14 15:10:12
字體:
來源:轉載
供稿:網友

寫在前面:

java SE5 提供了一種新的類型 Java的枚舉類型,關鍵字 enum 可以將一組具名的值的有限集合創建為一種新的類型,而這些具名的值可以作為常規的程序組件使用,這是一種非常有用的功能。本文將深入分析枚舉的源碼,看一看枚舉是怎么實現的,是如何保證線程安全的,以及為什么用枚舉實現的單例是最佳方式。

枚舉是如何保證線程安全的

要想看源碼,首先得有一個類吧,那么枚舉類型到底是什么類呢?是enum嗎?答案很明顯不是,enum就和class一樣,只是一個關鍵字,他并不是一個類,那么枚舉是由什么類維護的呢,我們簡單的寫一個枚舉:

1
2
3
public enum t {
    SPRING,SUMMER,AUTUMN,WINTER;
}

然后我們使用反編譯,看看這段代碼到底是怎么實現的,反編譯(Java的反編譯)后代碼內容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public final class T extends Enum
{
    private T(String s, int i)
    {
        super(s, i);
    }
    public static T[] values()
    {
        T at[];
        int i;
        T at1[];
        System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0, i);
        return at1;
    }
 
    public static T valueOf(String s)
    {
        return (T)Enum.valueOf(demo/T, s);
    }
 
    public static final T SPRING;
    public static final T SUMMER;
    public static final T AUTUMN;
    public static final T WINTER;
    private static final T ENUM$VALUES[];
    static
    {
        SPRING = new T("SPRING", 0);
        SUMMER = new T("SUMMER", 1);
        AUTUMN = new T("AUTUMN", 2);
        WINTER = new T("WINTER", 3);
        ENUM$VALUES = (new T[] {
            SPRING, SUMMER, AUTUMN, WINTER
        });
    }
}

通過反編譯后代碼我們可以看到,public final class T extends Enum,說明,該類是繼承了Enum類的,同時final關鍵字告訴我們,這個類也是不能被繼承的。當我們使用enmu來定義一個枚舉類型的時候,編譯器會自動幫我們創建一個final類型的類繼承Enum類,所以枚舉類型不能被繼承,我們看到這個類中有幾個屬性和方法。

我們可以看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static final T SPRING;
public static final T SUMMER;
public static final T AUTUMN;
public static final T WINTER;
private static final T ENUM$VALUES[];
static
{
    SPRING = new T("SPRING", 0);
    SUMMER = new T("SUMMER", 1);
    AUTUMN = new T("AUTUMN", 2);
    WINTER = new T("WINTER", 3);
    ENUM$VALUES = (new T[] {
        SPRING, SUMMER, AUTUMN, WINTER
    });
}

都是static類型的,因為static類型的屬性會在類被加載之后被初始化,我們在深度分析Java的ClassLoader機制(源碼級別)和Java類的加載、鏈接和初始化兩個文章中分別介紹過,當一個Java類第一次被真正使用到的時候靜態資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創建一個enum類型是線程安全的。

為什么用枚舉實現的單例是最好的方式

在[轉+注]單例模式的七種寫法中,我們看到一共有七種實現單例的方式,其中,Effective Java作者Josh Bloch 提倡使用枚舉的方式,既然大神說這種方式好,那我們就要知道它為什么好?

1. 枚舉寫法簡單

寫法簡單這個大家看看[轉+注]單例模式的七種寫法里面的實現就知道區別了。

1
2
3
public enum EasySingleton{
    INSTANCE;
}

你可以通過EasySingleton.INSTANCE來訪問。

2. 枚舉自己處理序列化

我們知道,以前的所有的單例模式都有一個比較大的問題,就是一旦實現了Serializable接口之后,就不再是單例得了,因為,每次調用 readObject()方法返回的都是一個新創建出來的對象,有一種解決辦法就是使用readResolve()方法來避免此事發生。但是,為了保證枚舉類型像Java規范中所說的那樣,每一個枚舉類型極其定義的枚舉變量在JVM中都是唯一的,在枚舉類型的序列化和反序列化上,Java做了特殊的規定。原文如下:

Enum constants are serialized differently than ordinary serializable or externalizable objects. The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form. To serialize an enum constant, ObjectOutputStream writes the value returned by the enum constant’s name method. To deserialize an enum constant, ObjectInputStream reads the constant name from the stream; the deserialized constant is then obtained by calling the java.lang.Enum.valueOf method, passing the constant’s enum type along with the received constant name as arguments. Like other serializable or externalizable objects, enum constants can function as the targets of back references appearing subsequently in the serialization stream. The process by which enum constants are serialized cannot be customized: any class-specific writeObject, readObject, readObjectNoData, writeReplace, and readResolve methods defined by enum types are ignored during serialization and deserialization. Similarly, any serialPersistentFields or serialVersionUID field declarations are also ignored–all enum types have a fixedserialVersionUID of 0L. Documenting serializable fields and data for enum types is unnecessary, since there is no variation in the type of data sent.

大概意思就是說,在序列化的時候Java僅僅是將枚舉對象的name屬性輸出到結果中,反序列化的時候則是通過java.lang.Enum的valueOf方法來根據名字查找枚舉對象。同時,編譯器是不允許任何對這種序列化機制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。 我們看一下這個valueOf方法:

1
2
3
4
5
6
7
8
9
public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) { 
            T result = enumType.enumConstantDirectory().get(name); 
            if (result != null
                return result; 
            if (name == null
                throw new NullPointerException("Name is null"); 
            throw new IllegalArgumentException( 
                "No enum const " + enumType +"." + name); 
        }

從代碼中可以看到,代碼會嘗試從調用enumType這個Class對象的enumConstantDirectory()方法返回的map中獲取名字為name的枚舉對象,如果不存在就會拋出異常。再進一步跟到enumConstantDirectory()方法,就會發現到最后會以反射的方式調用enumType這個類型的values()靜態方法,也就是上面我們看到的編譯器為我們創建的那個方法,然后用返回結果填充enumType這個Class對象中的enumConstantDirectory屬性。

所以,JVM對序列化有保證。

3.枚舉實例創建是thread-safe(線程安全的)

我們在深度分析Java的ClassLoader機制(源碼級別)和Java類的加載、鏈接和初始化兩個文章中分別介紹過,當一個Java類第一次被真正使用到的時候靜態資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創建一個enum類型是線程安全的。

全能程序員交流QQ群290551701,聚集很多互聯網精英,技術總監,架構師,項目經理!開源技術研究,歡迎業內人士,大牛及新手有志于從事IT行業人員進入!


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产91露脸中文字幕在线| 精品视频久久久久久| 国产精品福利无圣光在线一区| 亚洲最大成人网色| 伊人伊成久久人综合网小说| 久久网福利资源网站| 日本国产高清不卡| 欧美精品激情在线观看| 中文字幕在线精品| 富二代精品短视频| 日韩成人黄色av| 国产精品久久久久久av福利软件| 久久精品久久久久久国产 免费| 久久久欧美精品| 97色在线观看| 97在线免费观看| 亚洲网站视频福利| 日韩在线欧美在线国产在线| 亚洲精品国产品国语在线| 日韩精品一二三四区| 色综合久久88色综合天天看泰| 色午夜这里只有精品| 国产精品免费福利| 亚洲欧美日韩久久久久久| 欧美综合在线第二页| 精品五月天久久| 日韩成人在线免费观看| 国产精品精品久久久久久| 在线观看欧美成人| 中文字幕亚洲一区在线观看| 亚洲精品福利在线| 久久国产精品亚洲| 国产一区二区三区三区在线观看| 亚洲人成伊人成综合网久久久| 日韩在线观看网址| 国产综合在线视频| 国产欧美久久一区二区| 亚洲第一精品自拍| 一区二区在线免费视频| 日韩中文综合网| 国产精品国产福利国产秒拍| 亚洲91精品在线| 日韩最新中文字幕电影免费看| 亚洲欧美综合另类中字| 成人国产精品久久久久久亚洲| 久久久精品日本| 亚洲人成在线观看| 亚洲区在线播放| 17婷婷久久www| 91午夜理伦私人影院| 97在线观看视频国产| 日韩av123| 日韩第一页在线| 97香蕉超级碰碰久久免费的优势| 国产午夜精品全部视频在线播放| 久久久精品网站| 久久久国产一区二区| 91亚洲精品在线观看| 日本老师69xxx| 97高清免费视频| 日韩成人在线观看| 久久精品国产欧美激情| 欧美高清视频在线观看| 久久全国免费视频| 操91在线视频| 久久久人成影片一区二区三区观看| 欧美性生交大片免网| 国产日韩中文字幕| 亚洲欧美日韩中文在线制服| 538国产精品视频一区二区| 亚洲综合在线中文字幕| 亚洲第一区中文99精品| 亚洲网站视频福利| 欧美性猛交xxxx免费看| 亚洲视频在线视频| 欧美另类极品videosbest最新版本| 亚洲午夜色婷婷在线| 亚洲国产精品字幕| 欧美国产日韩二区| 成人国产亚洲精品a区天堂华泰| 亚洲成人1234| 国产精品露脸av在线| 亚洲国产精品大全| 久久久精品国产一区二区| 亚洲电影av在线| 欧美日韩国产91| 国产精品免费网站| 亚洲国产精品久久精品怡红院| 久久精品国产亚洲精品2020| 久久国产天堂福利天堂| 国产精品观看在线亚洲人成网| 国产精品免费看久久久香蕉| 成人免费福利视频| 97精品伊人久久久大香线蕉| 91精品国产乱码久久久久久久久| 日韩av电影手机在线观看| 91日本视频在线| 亚洲国产精品久久91精品| 日韩精品免费综合视频在线播放| 亚洲一区二区三区视频| 精品女同一区二区三区在线播放| 日韩av电影免费观看高清| 精品欧美国产一区二区三区| 亚洲免费视频在线观看| 久久久久久香蕉网| 激情久久av一区av二区av三区| 亚洲片国产一区一级在线观看| 欧美精品激情blacked18| 亚洲精品视频免费| 亚洲视频精品在线| 日韩资源在线观看| 国产精品一区二区女厕厕| 国产精品欧美亚洲777777| 国产一区二区三区在线看| 精品偷拍各种wc美女嘘嘘| 亚洲伊人成综合成人网| 亚洲国产女人aaa毛片在线| 亚洲成av人影院在线观看| 久久久久久中文| 国产极品jizzhd欧美| 欧美精品video| 亚洲a级在线播放观看| 国产精品欧美一区二区| 欧美激情视频网站| 91久久久亚洲精品| 欧美激情性做爰免费视频| 精品国偷自产在线| 久久免费视频网| 日韩精品免费在线| 国产精品精品久久久久久| 亚洲成人动漫在线播放| 亚洲一区二区三区777| 欧美在线亚洲在线| 欧美精品在线看| 欧美日韩国产成人在线| 日韩精品亚洲精品| 欧美影院成年免费版| 91精品国产自产在线老师啪| 精品欧美国产一区二区三区| 在线观看91久久久久久| 国产精品夜色7777狼人| 91久久精品日日躁夜夜躁国产| 国产国语刺激对白av不卡| 亚洲午夜av电影| 欧美老女人xx| 亚洲春色另类小说| 色婷婷久久av| 国产精品日韩专区| 国产69精品久久久| 91精品国产免费久久久久久| 日韩中文在线中文网三级| 97在线视频免费| 欧美日韩国产一区中文午夜| 91久久精品美女高潮| 久久久最新网址| 九色成人免费视频| 国产精品日日摸夜夜添夜夜av| 亚洲欧洲av一区二区| 国产成人精品一区| 日韩麻豆第一页| 亚洲精品美女在线观看| xxx欧美精品| 国产一区视频在线播放| 色婷婷综合久久久久中文字幕1|