對于比較穩定的值集合,Java 提供了枚舉來定義,通過它可以很友善管理集合。那麼 Java 的枚舉是通過怎樣的機制實作的?本文将從 JDK 角度來看看枚舉的原理。
使用很簡單,比如定義一個表示“環保”、“交通”、“手機”三個值的集合,那麼就可以直接定義如下,然後可直接 Labels.ENVIRONMENT 使用,
同時也可以使用帶構造函數的枚舉,如下,可以通過 getName 擷取值。
Java中的枚舉的實作機制是怎樣的?枚舉看起來有點像上帝扔給我們的文法糖,秉着深入挖一挖的精神,看看枚舉是相關實作,看看編譯器做了什麼。用 javap 看上面兩個枚舉編譯後的位元組碼:
可以清晰地看到枚舉被編譯後其實就是一個類,該類被聲明成 final,說明其不能被繼承,同時它繼承了 Enum 類。枚舉裡面的元素被聲明成 static final ,另外生成一個靜态代碼塊 static{},最後還會生成 values 和 valueOf 兩個方法。下面以最簡單的 Labels 為例,一個一個子產品來看。
Enum 類是一個抽象類,主要有 name 和 ordinal 兩個屬性,分别用于表示枚舉元素的名稱和枚舉元素的位置索引,而構造函數傳入的兩個變量剛好與之對應。
toString 方法直接傳回 name。
equals 方法直接用 == 比較兩個對象。
hashCode 方法調用的是父類的 hashCode 方法。
枚舉不支援 clone、finalize 和 readObject 方法。
compareTo 方法可以看到就是比較 ordinal 的大小。
valueOf 方法,根據傳入的字元串 name 來傳回對應的枚舉元素。
可以看到靜态代碼塊主要完成的工作就是先分别建立 Labels 對象,然後将“ENVIRONMENT”、“TRAFFIC”和“PHONE”字元串作為 name ,按照順序分别配置設定位置索引0、1、2作為 ordinal,然後将其值設定給建立的三個 Labels 對象的 name 和 ordinal 屬性,此外還會建立一個大小為3的 Labels 數組 ENUM$VALUES,将前面建立出來的 Labels 對象分别指派給數組。
可以看到它是一個靜态方法,主要是使用了前面靜态代碼塊中的 Labels 數組 ENUM$VALUES,調用 System.arraycopy 對其進行複制,然後傳回該數組。是以通過 <code>Labels.values()[2]</code>就能擷取到數組中索引為2的元素。
該方法同樣是個靜态方法,可以看到該方法的實作是間接調用了父類 Enum 類的 valueOf 方法,根據傳入的字元串 name 來傳回對應的枚舉元素,比如可以通過 <code>Labels.valueOf("ENVIRONMENT")</code>擷取 <code>Labels.ENVIRONMENT</code>。
枚舉本質其實也是一個類,而且都會繼承java.lang.Enum類,同時還會生成一個靜态代碼塊 static{},并且還會生成 values 和 valueOf 兩個方法。而上述的工作都需要由編譯器來完成,然後我們就可以像使用我們熟悉的類那樣去使用枚舉了。
-------------推薦閱讀------------
<a href="http://blog.csdn.net/wangyangzhizhou/article/details/78941458">2017文章彙總——機器學習篇</a>
<a href="http://blog.csdn.net/wangyangzhizhou/article/details/78928107">2017文章彙總——Java及中間件</a>
<a href="http://blog.csdn.net/wangyangzhizhou/article/details/78878909">2017文章彙總——深度學習篇</a>
<a href="http://blog.csdn.net/wangyangzhizhou/article/details/78994519">2017文章彙總——JDK源碼篇</a>
------------------廣告時間----------------
公衆号的菜單已分為“分布式”、“機器學習”、“深度學習”、“NLP”、“Java深度”、“Java并發核心”、“JDK源碼”、“Tomcat核心”等,可能有一款适合你的胃口。
鄙人的新書《Tomcat核心設計剖析》已經在京東銷售了,有需要的朋友可以購買。感謝各位朋友。
<a href="http://blog.csdn.net/wangyangzhizhou/article/details/74080321">為什麼寫《Tomcat核心設計剖析》</a>
歡迎關注:
