[轉載] java 枚舉Enum源碼解析

參考鏈接: 使用Java枚舉

應用場景?

枚舉是單例模式中的一種。面試官系統之設計模式(單例模式)?

簡單來講就是只能實例化一次,線程安全且性能高。枚舉通常用來列舉一個類型的有限實例集合,我們可以使用常量集來實現,jdk1.5添加了枚舉(enum)支持,解決了常量集的一些缺陷?

常量集中的變量不會必然在指定的范圍內常量能夠提供的功能很少,難于使用常量意義不明確,沒有名字修改或增加枚舉值后需要修改的代碼多,不便于維護

關鍵字enum可以將一組具名的值的有限集合創建為一種新的類型,而這些具名的值可以作為常規的組件使用。?

??

一、定義?

//Enum類是java.lang包中一個類,他是Java語言中所有枚舉類型的公共基類。

public abstract class Enum<E extends java.lang.Enum<E>> implements Comparable<E>, Serializable?

1.抽象類。?

首先,抽象類不能被實例化,所以我們在java程序中不能使用new關鍵字來聲明一個Enum,所以枚舉一旦創建就只有一個實例。?

如果想要定義可以使用這樣的語法:?

enum enumName{

? ? value1,value2

? ? method1(){}

? ? method2(){}

}?

其次,看到抽象類,第一印象是肯定有類繼承他。至少我們應該是可以繼承他的,所以:?

public class testEnum extends Enum{

}

public class testEnum extends Enum<Enum<E>>{

}

public class testEnum<E> extends Enum<Enum<E>>{

}?

嘗試了以上三種方式之后,得出以下結論:Enum類無法被繼承。?

為什么一個抽象類不讓繼承?enum定義的枚舉是怎么來的?難道不是對Enum的一種繼承嗎?帶著這些疑問我們來反編譯以下代碼:?

? enum Color {RED, BLUE, GREEN}?

編譯器將會把他轉成如下內容:?

public final class Color extends Enum<Color> {

? public static final Color[] values() { return (Color[])$VALUES.clone(); }

? public static Color valueOf(String name) { ... }

?

? private Color(String s, int i) { super(s, i); }

?

? public static final Color RED;

? public static final Color BLUE;

? public static final Color GREEN;

?

? private static final Color $VALUES[];

?

? static {

? ? RED = new Color("RED", 0);

? ? BLUE = new Color("BLUE", 1);

? ? GREEN = new Color("GREEN", 2);

? ? $VALUES = (new Color[] { RED, BLUE, GREEN });

? }

}??

我們看到當我們定義一個枚舉,編譯器其實是為我們創建了一個繼承自Emum的類?

??

枚舉實例對應新類中的static final 變量該類為 final類型,不可被繼承增加了兩個方法??

? valueOf(String) 從String構造枚舉類型values() 返回一個由枚舉對象構成的數組添加了一個靜態初始化器 static{},用來初始化枚舉實例,和枚舉實例數組,也就是 values()返回數組

PS:由于JVM類初始化是線程安全的,所以可以采用枚舉類實現一個線程安全的單例模式。?

??

2.實現Comparable和Serializable接口。?

??

Enum實現了Serializable接口,可以序列化。 Enum實現了Comparable接口,可以進行比較,默認情況下,只有同類型的enum才進行比較(原因見后文),要實現不同類型的enum之間的比較,只能復寫compareTo方法。?

3.泛型:**<E extends Enum<E>>**?

怎么理解<E extends Enum<E>>??

?

?首先,這樣寫只是為了讓Java的API更有彈性,他主要是限定形態參數實例化的對象,故要求只能是Enum,這樣才能對 compareTo 之類的方法所傳入的參數進行形態檢查。所以,我們完全可以不必去關心他為什么這么設計。?

?

這里倒是可以關注一下泛型中extends的用法,以及K V O T E ? object這幾個符號之間的區別。?

好啦,我們回到這個令人實在是無法理解的<E extends Enum<E>>?

首先我們先來“翻譯”一下這個Enum<E extends Enum<E>>到底什么意思,然后再來解釋為什么Java要這么用。 我們先看一個比較常見的泛型:List<String>。這個泛型的意思是,List中存的都是String類型,告訴編譯器要接受String類型,并且從List中取出內容的時候也自動幫我們轉成String類型。 所以Enum<E extends Enum<E>>可以暫時理解為Enum里面的內容都是E extends Enum<E>類型。 這里的E我們就理解為枚舉,extends表示上界,比如: List<? extends Object>,List中的內容可以是Object或者擴展自Object的類。這就是extends的含義。 所以,E extends Enum<E>表示為一個繼承了Enum<E>類型的枚舉類型。 那么,Enum<E extends Enum<E>>就不難理解了,就是一個Enum只接受一個Enum或者他的子類作為參數。相當于把一個子類或者自己當成參數,傳入到自身,引起一些特別的語法效果。?

為什么Java要這樣定義Enum?

首先我們來科普一下enum,?

enum Color{

? ? RED,GREEN,YELLOW

}

enum Season{

? ? SPRING,SUMMER,WINTER

}

public class EnumTest{

? ? public static void main(String[] args) {

? ? ? ? System.out.println(Color.RED.ordinal());

? ? ? ? System.out.println(Season.SPRING.ordinal());

? ? }

}?

代碼中兩處輸出內容都是 0 ,因為枚舉類型的默認的序號都是從零開始的。?

要理解這個問題,首先我們來看一個Enum類中的方法(暫時忽略其他成員變量和方法):?

public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {

? ? private final int ordinal;

?

? ? public final int compareTo(E o) {

? ? ? ? Enum<?> other = (Enum<?>)o;

? ? ? ? Enum<E> self = this;

?

? ? ? ? if (self.getClass() != other.getClass() && // optimization

? ? ? ? ? ? self.getDeclaringClass() != other.getDeclaringClass())

? ? ? ? ? ? throw new ClassCastException();

? ? ? ? return self.ordinal - other.ordinal;

? ? }

}?

首先我們認為Enum的定義中沒有使用Enum<E extends Enum<E>>,那么compareTo方法就要這樣定義(因為沒有使用泛型,所以就要使用Object,這也是Java中很多方法常用的方式):?

public final int compareTo(Object o)??

當我們調用compareTo方法的時候依然傳入兩個枚舉類型,在compareTo方法的實現中,比較兩個枚舉的過程是先將參數轉化成Enum類型,然后再比較他們的序號是否相等。那么我們這樣比較:?

Color.RED.compareTo(Color.RED);

Color.RED.compareTo(Season.SPRING);?

如果在compareTo方法中不做任何處理的話,那么以上這段代碼返回內容將都是true(因為Season.SPRING的序號和Color.RED的序號都是 0 )。但是,很明顯, Color.RED和Season.SPRING并不相等。?

但是Java使用Enum<E extends Enum<E>>聲明Enum,并且在compareTo的中使用E作為參數來避免了這種問題。 以上兩個條件限制Color.RED只能和Color定義出來的枚舉進行比較,當我們試圖使用Color.RED.compareTo(Season.SPRING);這樣的代碼是,會報出這樣的錯誤:?

The method compareTo(Color) in the type Enum<Color> is not applicable for the arguments (Season)?

他說明,compareTo方法只接受Enum<Color>類型。?

Java為了限定形態參數實例化的對象,故要求只能是Enum,這樣才能對 compareTo之類的方法所傳入的參數進行形態檢查。 因為“紅色”只有和“綠色”比較才有意義,用“紅色”和“春天”比較毫無意義,所以,Java用這種方式一勞永逸的保證像compareTo這樣的方法可以正常的使用而不用考慮類型。?

?

?PS:在Java中,其實也可以實現“紅色”和“春天”比較,因為Enum實現了Comparable接口,可以重寫compareTo方法來實現不同的enum之間的比較。?

?

二、成員變量?

在Enum中,有兩個成員變量,一個是名字(name),一個是序號(ordinal)。 序號是一個枚舉常量,表示在枚舉中的位置,從0開始,依次遞增。?

/**

?* @author hollis

?*/

private final String name;

public final String name() {

? ? return name;

}

private final int ordinal;

public final int ordinal() {

? ? return ordinal;

}?

三、構造函數?

前面我們說過,Enum是一個抽象類,不能被實例化,但是他也有構造函數,從前面我們反編譯出來的代碼中,我們也發現了Enum的構造函數,在Enum中只有一個保護類型的構造函數:?

protected Enum(String name, int ordinal) {

? ? this.name = name;

? ? this.ordinal = ordinal;

}?

文章開頭反編譯的代碼中private Color(String s, int i) { super(s, i); }中的super(s, i);就是調用Enum中的這個保護類型的構造函數來初始化name和ordinal。?

四、方法?

序列化?

禁止了基礎的序列化方法,調用readObject()和writeObject()時拋出異常

? ? protected final void finalize() {

? ? }

? ? private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {

? ? ? ? throw new InvalidObjectException("can't deserialize enum");

? ? }

? ? private void readObjectNoData() throws ObjectStreamException {

? ? ? ? throw new InvalidObjectException("can't deserialize enum");

? ? }?

??

??

??

參照:?

(1)https://blog.csdn.net/stubbornant/article/details/51480727?

(2)http://www.hollischuang.com/archives/92

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/540398.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/540398.shtml
英文地址,請注明出處:http://en.pswp.cn/news/540398.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

聊聊全站HTTPS帶來的技術挑戰

日前寫的文章里了討論了數據傳輸的安全性的問題&#xff0c;最后一部分提到了通過HTTPS解決數據傳輸安全性的方案。那么一個新問題又來了&#xff0c;實施全站HTTPS的過程中&#xff0c;我們可能會遇到哪些技術問題?所以我今天和大家一起來算一下這個賬&#xff0c;將技術成本…

[轉載] spring mvc自定義int枚舉轉換器

參考鏈接&#xff1a; Java中具有自定義值的枚舉 2019獨角獸企業重金招聘Python工程師標準>>> public class MyIntegerEnumConverters { WritingConverter public static class EnumToIntegerConverter implements Converter<IntEnumConvertable, String> {…

使用BufferedImage進行漸變色操作

序 本文主要簡述一下如何使用BufferedImage進行漸變色操作。 GradientPaint java/awt/GradientPaint.java public class GradientPaint implements Paint {Point2D.Float p1;Point2D.Float p2;Color color1;Color color2;boolean cyclic;//...... } 這個是生成漸變色的關…

[轉載] Java中的字符串處理

參考鏈接&#xff1a; Java中的StringBuffer appendCodePoint()方法以及示例 JDK8在線Api中文手冊 JDK8在線Api英文手冊 Java中的字符串處理 1.1 String類的構造函數1.2 字符串的長度1.3 特殊的字符串操作1.3.1 字符串字面值1.3.2 字符串連接1.3.3 字符串和其他數據類型的連…

MySQL循環語句之while循環測試

轉自&#xff1a;http://www.nuoweb.com/database/7614.htmlMySQL有循環語句操作&#xff0c;while 循環、loop循環和repeat循環&#xff0c;目前我只測試了 while 循環&#xff0c;下面與大家分享下mysql 操作同樣有循環語句操作&#xff0c;網上說有3中標準的循環方式&#x…

[轉載] JAVA環境變量配置

參考鏈接&#xff1a; Java中的變量 安裝JDK(1.8) Oracle官網 下載jdk 百度網盤window版本 提取碼&#xff1a;o99i win 10環境變量配置 在電腦桌面 右鍵點擊 此電腦 的 屬性 選項 選擇 高級系統設置 > 然后點擊 環境變量 選項 點擊 系統變量 下的 新建 按鈕&#xf…

[轉載] Java中的變量和常量

參考鏈接&#xff1a; Java中的變量范圍 在程序中存在大量的數據來代表程序的狀態&#xff0c;其中有些數據在程序的運行過程中值會發生改變&#xff0c;有些數據在程序運行過程中值不能發生改變&#xff0c;這些數據在程序中分別被叫做變量和常量。 在實際的程序中&#xf…

4.3/4.4 磁盤分區

2019獨角獸企業重金招聘Python工程師標準>>> 添加虛擬磁盤 第一步&#xff0c;選擇虛擬機中的“設置” 第二步&#xff0c;選擇“添加硬盤” 第三步&#xff0c;選擇_SCSI &#xff08;推薦&#xff09; # 保持默認 第四步&#xff0c;選擇“創建新的虛擬磁盤…

[轉載] java(三)對象的序列化與static、final關鍵字

參考鏈接&#xff1a; Java中的final最終變量 java對象的序列化 Java序列化是指把Java對象轉換為字節序列的過程&#xff1b;而Java反序列化是指把字節序列恢復為Java對象的過程。java中存有Cloneable接口&#xff0c;實現此接口的類都具有被拷貝能力&#xff0c;比new一個對象…

RoboMaster 2017:機器人版的「王者農藥」,工程師們的競技時代

8月6日晚&#xff0c;第十六屆全國大學生機器人大賽 RoboMaster 2017機甲大師賽在華潤深圳灣體育中心“春繭”體育館舉行&#xff0c;關于這個比賽的盛況已經無需贅述&#xff0c;去年雷鋒網參加上屆比賽時&#xff0c;報道的是「像看了一場演唱會」&#xff0c;如果用演唱會來…

[轉載] 詳解Java中的泛型

參考鏈接&#xff1a; Java中具有泛型的有界類型 1、什么是泛型 泛型&#xff0c;即“參數化類型”。一提到參數&#xff0c;最熟悉的就是定義方法時有形參&#xff0c;然后調用此方法時傳遞實參。那么參數化類型怎么理解呢&#xff1f;顧名思義&#xff0c;就是將類型由原來…

【初學者必讀】:前端工程師的知識體系

下圖是前端工程師圖解&#xff1a; 前端開發的核心是HTML CSS JavaScript。本質上它們構成一個MVC框架&#xff0c;即HTML作為信息模型&#xff08;Model&#xff09;&#xff0c;CSS控制樣式&#xff08;View&#xff09;&#xff0c;JavaScript負責調度數據和實現某種展現邏…

[轉載] Java面試題大全(2020版)

參考鏈接&#xff1a; Java中的循環 發現網上很多Java面試題都沒有答案&#xff0c;所以花了很長時間搜集整理出來了這套Java面試題大全&#xff0c;希望對大家有幫助哈~ 本套Java面試題大全&#xff0c;全的不能再全&#xff0c;哈哈~ 博主已將以下這些面試題整理成了一個…

使用Prometheus監控Cloudflare的全球網絡

Matt Bostock在SRECON 2017歐洲大會的演講中&#xff0c;介紹了如何使用Prometheus實現對CloudFlare分布于全球的架構和網絡的監控。Prometheus是一種基于度量進行監控的工具&#xff0c;CloudFlare是一家CDN、DNS和DDoS防御&#xff08;Mitigation&#xff09;服務提供商。\\基…

[轉載] Java-forEach增強for循環是值傳遞規則詳解

參考鏈接&#xff1a; Java中的for-each循環 1. 引入 正如Java語法意義&#xff0c;變量的傳遞只有值傳遞&#xff0c;雖然變量分為引用變量和基本類型變量&#xff0c;前者更像C中的地址概念。 在學習Lambda表達式的時候&#xff0c;遇到了試圖在增強for循環中對原鏈表元素重…

開始吧

2019獨角獸企業重金招聘Python工程師標準>>> 寫C三年有余&#xff0c;在技術方面也算小有所成。準備在這里分享一些C進階、Python、Golang技術文章。 CSDN博客地址&#xff1a; http://blog.csdn.net/godmaycry 以后博客同步更新。 轉載于:https://my.oschina.net/u…

[轉載] 常用應屆生Java開發筆試面試題(更新中)

參考鏈接&#xff1a; Java中的循環的重要事項 Java開發面試題 Java基礎篇Java8大基本數據類型Java的三大特性面向對象如果讓你推銷一款Java產品&#xff0c;你會怎么推銷呢&#xff1f;&#xff08;java的特點&#xff09;JVM與字節碼JDK與JREStringBuilder和StringBuffer的區…

java/javascript 時間操作工具類

一、java 時間操作工具類 import org.springframework.util.StringUtils;import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.List;/*** 時間操作工具類** author zwq**/ public …

[轉載] java語言程序設計-基礎篇

參考鏈接&#xff1a; Java中的決策制定(if&#xff0c;if-else&#xff0c;switch&#xff0c;break&#xff0c;continue&#xff0c;jump) 第1章&#xff0c;計算機、程序和Java概述 包括【每個java初學者都應該搞懂的問題】 http://blog.csdn.net/haobo920/article/detai…

Exchange server 2013(十四)WSUS部署及組策略設置(2)

我們繼續上一節未完的博客&#xff0c;繼續我們的WSUS設置。[上一章節標題&#xff1a;Exchange server 2013(十四)WSUS部署及組策略設置(1) 網址&#xff1a;http://1183839.blog.51cto.com/blog/1173839/1182366] 首先單擊自動審批,來修改審批規則,也就是說當wsus偵測到新的更…