日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 枚举(enum) 全面解读

發布時間:2025/3/12 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 枚举(enum) 全面解读 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

枚舉類型是單例模式的。你需要實例化一次,然后再整個程序之中就可以調用他的方法和成員變量了。
枚舉類型使用單例模式是因為他的值是固定的,不需要發生改變。

簡介

枚舉是Java1.5引入的新特性,通過關鍵字enum來定義枚舉類。枚舉類是一種特殊類,它和普通類一樣可以使用構造器、定義成員變量和方法,也能實現一個或多個接口,但枚舉類不能繼承其他類.

原理分析

枚舉類型使用的最常用類型就是枚舉常量.下面通過一個簡單的Demo來說明枚舉的原理.

這樣只是能夠知道枚舉簡單的使用方法,不能看出枚舉的特點和枚舉的具體實現.

下面我們通過 jad工具來反編譯Color類, 通過jad -sjava Color.class反編譯出一份java文件.

從反編譯的類中,可以看出, 我們使用enum關鍵字編寫的類,在編譯階段編譯器會自動幫我們生成一份真正在jvm中運行的代碼.

該類繼承自 Enum類,public abstract class Enum>implements Comparable, Serializable.

Enum類接受一個繼承自Enum的泛型.(在反編譯java文件中沒有體現泛型是因為,泛型在階段就會被類型類型擦除,替換為具體的實現.).

從反編譯的Color類中可以看出,在enum關鍵字的類中,第一行 **(準確的說是第一個分號前)**定義的變量,都會生成一個 Color實例,且它是在靜態域中進行初始化的, 而靜態域在類加載階段的cinit中進行初始化,所以枚舉對象是線程安全的,由JVM來保證.

生成的枚舉類有 **Color $VALUES[];**成員變量,外部可以通過values()方法獲取當前枚舉類的所有實例對象.

Enum成員變量和方法分析

Enum成員變量

Enum成員變量和方法

Enum類實現了 Comparable接口,表明它是支持排序的,可以通過 Collections.sort 進行自動排序.實現了**public final int compareTo(E o)**接口,方法定義為final且其實現依賴的ordinal字段也是final類型,說明他只能根據ordinal排序,排序規則不可變.

ordinal: 表示枚舉的順序,從Color類中可以看出,它是從0開始按自然數順序增長,且其值是final類型,外部無法更改.對于 ordinal()方法,官方建議盡量不要使用它,它主要是提供給EnumMap,EnumSet使用的.

name: 表示枚舉類的名字,從Color類的構造函數可以看出,它的值就是我們定義的實例的名稱.

我們在例子中之所以能打印出實例名稱,是因為 它的toString()方法直接返回了name屬性.

equals(): 從其實現來看, 我們程序中使用 == 或者 equals來判斷兩個枚舉相等都是一樣的.

getDeclaringClass(): 方法返回枚舉聲明的Class對象

每一個枚舉類型極其定義的枚舉變量在JVM中都是唯一的

這句話的意思是枚舉類型它擁有的實例在編寫的時候,就已經確定下,不能通過其他手段進行創建,且枚舉變量在jvm有且只有一個對應的實例.

為了達到這個效果,它通過以下方法來確保.

1. 類加載時創建,保證線程安全

從Color類中可以看出, Color對象是在靜態域創建,由類加載時初始化,JVM保證線程安全,這樣就能確保Color對象不會因為并發同時請求而錯誤的創建多個實例.

2. 對序列化進行特殊處理,防止反序列化時創建新的對象

我們知道一旦實現了Serializable接口之后,反序列化時每次調用 readObject()方法返回的都是一個新創建出來的對象.

而枚舉則不同,在序列化的時候Java僅僅是將枚舉對象的name屬性輸出到結果中,反序列化的時候則是通過Enum的valueOf()方法來根據名字查找枚舉對象。同時,編譯器是不允許任何對這種序列化進行定制,因此禁用了writeObjectreadObjectreadObjectNoDatawriteReplacereadResolve等方法。

1.私有構造函數, 無法正常的 new出對象

2.無法通過 clone()方法,克隆對象

3. 無法通過反射的方式創建枚舉對象

枚舉類型,在 JVM 層面禁止了通過反射構造枚舉實例的行為,如果嘗試通過反射創建,將會報Cannot reflectively create enum objects.

枚舉類的特點總結

  • 枚舉實例必須在 enum關鍵字聲明的類中顯式的指定(首行開始的以第一個分號結束)
  • 除了1, 沒有任何方式(new,clone,反射,序列化)可以手動創建枚舉實例
  • 枚舉類不可被繼承
  • 枚舉類是線程安全的
  • 枚舉類型是類型安全的(typesafe)
  • 無法繼承其他類(已經默認繼承Enum)
  • 枚舉的使用

    • 枚舉常量

    如上訴 Color枚舉類,就是典型的枚舉常量.

    它可以在 switch語句中使用

    枚舉類型是類型安全的,可以對傳入的值進行類型檢查:

    如有個 handleColor(Color color)方法,那么方法參數自動會對類型進行檢查,只能傳入 Color.WHITEColor.BLACK,如果使用 static final定義的常量則不具備 類型安全的特點.

    • 枚舉與構造函數

    枚舉類可以編寫自己的構造函數,但是不能聲明public,protected,為了是不讓外部創建實例對象,默認為private且只能為它.

    • 枚舉與類

    除了枚舉常量外, enum是一個完整的類,它也可以編寫自己的構造方法以及方法,甚至實現接口.

    這里需要注意,枚舉類不能繼承其他類,因為在編譯時它已經繼承了 Enum,java無法多繼承

    枚舉與單例模式

    單例模式網上有6-7中寫法,除了 枚舉方式外, 都有兩個致命的缺點, 不能完全保證單例在jvm中保持唯一性.

    1. 反射創建單例對象

    解決方案 : 在構造上述中判斷,當多于一個實例時,再調用構造函數,直接報錯.

    2. 反序列化時創建對象

    解決方案 : 使用**readResolve()**方法來避免此事發生.

    這兩種缺點雖然都有方式解決,但是不免有些繁瑣.

    枚舉類天生有這些特性.而且實現單例相當簡單.

    所以,枚舉實現的單例,可以說是最完美和簡潔的單例了.推薦大家使用這種方式創建單例.

    但是,枚舉類的裝載和初始化時會有時間和空間的成本. 它的實現比其他方式需要更多的內存空間,所以在Android這種受資源約束的設備中盡量避免使用枚舉單例,而選擇 雙重檢查鎖(DCL)和靜態內部類的方式實現單例.

    枚舉與策略模式

    特定的常量類型與主體中的方法或行為有關時,即當數據與行為之間有關聯時,可以考慮使用枚舉來實現策略模式.

    如我們需要實現加減運算,就可以在枚舉類型中聲明一個 apply抽象方法,在特定于常量的方法(Constant-specific class body的Constant -specific method implementation)中,用具體實現抽象方法.

    總結

    以上是生活随笔為你收集整理的java 枚举(enum) 全面解读的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。