JDK源碼學習筆記——Enum枚舉使用及原理

一、為什么使用枚舉

什么時候應該使用枚舉呢?每當需要一組固定的常量的時候,如一周的天數、一年四季等。或者是在我們編譯前就知道其包含的所有值的集合。

利用 public final static 完全可以實現的功能,為什么要使用枚舉?

public class Season {public static final int SPRING = 1;public static final int SUMMER = 2;public static final int AUTUMN = 3;public static final int WINTER = 4;
}

(1)安全性。這種模式不是類型安全的。比如說我們設計一個函數,要求傳入春夏秋冬的某個值。但是使用int類型,我們無法保證傳入的值為合法。如:傳入5。

(2)可讀性。我們需要方便得到枚舉類型的字符串表達式。int常量打印出來,我們所見到的就是一組數字,沒什么用;String常量可以打印出詳細信息,但是字符串的比較操作性能較低。

二、枚舉的幾種使用方式

用法一:常量

public enum Color {  RED, GREEN, BLANK, YELLOW  
}  

用法二:switch

enum Signal {  GREEN, YELLOW, RED  
}  
public class TrafficLight {  Signal color = Signal.RED;  public void change() {  switch (color) {  case RED:  color = Signal.GREEN;  break;  case YELLOW:  color = Signal.RED;  break;  case GREEN:  color = Signal.YELLOW;  break;  }  }  
}  

用法三:向枚舉中添加新方法

public enum Color {  RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);  // 成員變量  private String name;  private int index;  // 構造方法  private Color(String name, int index) {  this.name = name;  this.index = index;  }  // 普通方法  public static String getName(int index) {  for (Color c : Color.values()) {  if (c.getIndex() == index) {  return c.name;  }  }  return null;  }  // get set 方法  public String getName() {  return name;  }  public void setName(String name) {  this.name = name;  }  public int getIndex() {  return index;  }  public void setIndex(int index) {  this.index = index;  }  
} 

用法四:覆蓋枚舉的方法

public enum Color {  RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);  // 成員變量  private String name;  private int index;  // 構造方法  private Color(String name, int index) {  this.name = name;  this.index = index;  }  //覆蓋方法  
    @Override  public String toString() {  return this.index+"_"+this.name;  }  
}  

用法五:實現接口

public interface Behaviour {  void print();  String getInfo();  
}  
public enum Color implements Behaviour{  RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);  // 成員變量  private String name;  private int index;  // 構造方法  private Color(String name, int index) {  this.name = name;  this.index = index;  }  
//接口方法  
    @Override  public String getInfo() {  return this.name;  }  //接口方法  
    @Override  public void print() {  System.out.println(this.index+":"+this.name);  }  
} 

用法六:使用接口組織枚舉

public interface Food {  enum Coffee implements Food{  BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO  }  enum Dessert implements Food{  FRUIT, CAKE, GELATO  }  
}

三、原理(代碼易懂,不做詳細介紹)

enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}// 反編譯之后如下:
// 反編譯Day.class
final class Day extends Enum
{//編譯器為我們添加的靜態的values()方法public static Day[] values(){return (Day[])$VALUES.clone();}//編譯器為我們添加的靜態的valueOf()方法,注意間接調用了Enum也類的valueOf方法public static Day valueOf(String s){return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);}//私有構造函數private Day(String s, int i){super(s, i);}//前面定義的7種枚舉實例public static final Day MONDAY;public static final Day TUESDAY;public static final Day WEDNESDAY;public static final Day THURSDAY;public static final Day FRIDAY;public static final Day SATURDAY;public static final Day SUNDAY;private static final Day $VALUES[];static {    //實例化枚舉實例MONDAY = new Day("MONDAY", 0);TUESDAY = new Day("TUESDAY", 1);WEDNESDAY = new Day("WEDNESDAY", 2);THURSDAY = new Day("THURSDAY", 3);FRIDAY = new Day("FRIDAY", 4);SATURDAY = new Day("SATURDAY", 5);SUNDAY = new Day("SUNDAY", 6);$VALUES = (new Day[] {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY});}
}

四、枚舉保證線程安全

由上面反編譯代碼可以看到,“ public static final Day MONDAY;?”,static類型的屬性會在類被加載之后被初始化,當一個Java類第一次被真正使用到的時候靜態資源被初始化、Java類的加載和初始化過程都是線程安全的。所以,創建一個enum類型是線程安全的。

JVM類加載機制中:

“?并發:

  虛擬機會保證一個類的類構造器<clinit>()在多線程環境中被正確的加鎖、同步,如果多個線程同時去初始化一個類,那么只會有一個線程去執行這個類的類構造器<clinit>(),其他線程都需要阻塞等待,直到活動線程執行<clinit>()方法完畢。

特別需要注意的是,在這種情形下,其他線程雖然會被阻塞,但如果執行<clinit>()方法的那條線程退出后,其他線程在喚醒之后不會再次進入/執行<clinit>()方法,因為在同一個類加載器下,一個類型只會被初始化一次。?”

?

?

參考資料 / 相關推薦:

Java 7 源碼學習系列(二)——Enum

Java基礎知識——枚舉

深入理解Java枚舉類型(enum)

【JAVA】淺談java枚舉類

Java 枚舉(enum) 詳解7種常見的用法

轉載于:https://www.cnblogs.com/hexinwei1/p/9606266.html

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

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

相關文章

Mybatis源碼日志模塊分析

看源碼需要先下載源碼&#xff0c;可以去Mybatis的github上的倉庫進行下載&#xff0c;Mybatis 這次就先整理一下日志這一塊的源碼分析&#xff0c;這塊相對來說比較簡單而且這個模塊是Mybatis的基礎模塊。 之前的文章有談到過Java的日志實現&#xff0c;大家也可以參考一下&…

python手機端給電腦端發送數據_期貨交易軟件有哪些比較好用?分手機端和電腦端...

一、電腦端交易軟件期貨電腦端交易軟件目前市場上用的最多的是文華財經和博易大師&#xff0c;這兩個軟件都是免費交易使用的。從投資者使用角度來看&#xff0c;目前電腦端文華財經的評價比博易大師高一些。當然每個投資者有自己的使用習慣&#xff0c;博易大師也有自己優點&a…

Find the Difference(leetcode389)

2019獨角獸企業重金招聘Python工程師標準>>> Given two strings s and t which consist of only lowercase letters. String t is generated by random shuffling string s and then add one more letter at a random position. Find the letter that was added in …

Mybatis源碼之數據源模塊分析

先來看看java純jdbc查詢數據的示例&#xff1a; try {//加載對應的驅動類Class.forName("com.mysql.cj.jdbc.Driver");//創建連接Connection connection DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test?serverTimezoneUTC", "roo…

reactnative 獲取定位_[RN] React Native 獲取地理位置

import React, {Component} from react;import {StyleSheet, Text, View}from react-native;exportdefault classTestGeo extends Component {state{longitude:,//經度latitude: ,//緯度city: ,district:,street:,position:,//位置名稱};componentWillMount () >{this.getPo…

第二沖刺階段第三天

查閱資料&#xff0c;修改控件界面轉載于:https://www.cnblogs.com/gyy0/p/10066452.html

Mybatis源碼之緩存模塊分析

緩存這個東西在很多應用中都能看到它們的身影&#xff0c;這次就講講在Mybatis中的緩存是怎么應用的&#xff0c;雖然說吧Mybatis中的緩存基本不怎么用&#xff0c;用的更多是第三方組件redis、MongoDB、MemCache等等。 Mybatis的緩存是基于Map實現的&#xff0c;從緩存中讀寫…

Mybatis源碼之核心流程分析

終于談到了Mybatis最核心的東西了&#xff0c;最核心的就是通過配置XML文件或注解中的SQL&#xff0c;直接調用接口就能執行配置好的SQL語句并封裝成對應的返回類型的數據。 先看一下Mybatis使用示例&#xff1a; //創建Builder對象 SqlSessionFactoryBuilder builder new S…

mimakatz用法_兩步完成利用procdump64+mimikatz獲取win用戶密碼

使用procdump64mimikatz可實現從內存中獲取明文密碼工具鏈接&#xff1a;https://pan.baidu.com/s/1gNc9qLcNSNBohIVrAiqShw 密碼&#xff1a;fc38首先得先獲取到內存文件lsass.exe進程, 它用于本地安全和登陸策略,一般在進程管理器中能看到, 比如這樣1.導出lsass.exeprocdump6…

ios app提交之前需要哪幾個證書

1、遇到的問題 一款App在別人的機器上開發和發布&#xff0c;現在迭代更新和開發需要在一臺新mac機上開發和發布。&#xff08;使用同一個開發者賬號&#xff09;問題&#xff1a; 1.在新mac機器上開發并導入真機測試&#xff0c;是不是需要從別人的機器上面導處開發者證書、開…

Mybatis源碼之與Spring集成包

這次講講Mybatis與Spring的整合&#xff0c;作為兩款優秀的開源框架&#xff0c;被大眾廣泛使用&#xff0c;自然是需要強強聯合的。 使用示例 先看一下怎么使用&#xff0c;首先需要引用這兩款框架的jar包&#xff1a; <dependency>//spring-webmvc會自動去引入其他S…

hadoop主節點切換_hadoop2.0 HA的主備自動切換

在《hadoop2.0 QJM方式的HA的配置》一文中介紹了HA的配置&#xff0c;是通過手工進行主備切換的。本文在這基礎上&#xff0c;繼續介紹HA的主備自動切換(automatic failover)的配置。自動切換是通過配置zookeeper來實現的&#xff0c;關于zookeeper的安裝和配置&#xff0c;在這…

Mybatis源碼之插件模塊分析

總結完這個Mybatis的整體主要功能基本上就差不多完&#xff0c;還有一些細節的部分&#xff0c;后續都會記錄補充。 插件這個東西一般用的比較少&#xff0c;就算用的多的插件也算是PageHelper分頁插件&#xff1b; PageHelper官網&#xff1a;https://github.com/pagehelper…

AMD推出7nm高端顯卡Radeon VII,直指英偉達RTX 2080

顯卡戰爭已經發展到了2019年&#xff0c;并且變得比任何人預想的都要激烈。 CES 2019大會上&#xff0c;AMD發布了第一款消費級的 7nm GPU&#xff0c;取名&#xff1a;Radeon VII。據了解&#xff0c;這不是 AMD 的第一顆 7nm 處理器&#xff08;早期以 AI 運算為主的 Radeon …

電子繪本pdf_【孩子必看的】20本世界著名英文繪本 | PDF電子版+MP3音頻

原標題&#xff1a;【孩子必看的】20本世界著名英文繪本 | PDF電子版MP3音頻2 —6歲年齡段的孩子&#xff0c;自我意識逐漸萌芽&#xff0c;已經明白書是一種“特殊”的玩具&#xff0c;不在撕書、咬書、把書搬來搬去。這個階段他們記憶力超強&#xff0c;唐詩、三字經啥的&…

Spring集成Mybatis多數據源配置

既然在整理Mybatis那就把經常用的這個多數據源的筆記也整一下吧。 Spring集成Mybatis在之前就已經提到了。Spring集成Mybatis 集成Mybatis多數據源有兩種方式&#xff1a; 1、創建多個SqlSessionFactory&#xff0c;掃描每個SqlSessionFactoryBean對應的包&#xff0c;形成了…

Spring文件上傳

2019獨角獸企業重金招聘Python工程師標準>>> Spring文件上傳 1、所需依賴包&#xff1a;commons-fileupload-1.3.1.jar2、Maven配置文件pom.xml文件中加入依賴Jar包<dependency><groupId>commons-fileupload</groupId><artifactId>commons-…

中英離線翻譯mac_Instant Translate for Mac-即時翻譯Mac版下載 V1.3.0-PC6蘋果網

即時翻譯(Instant Translate)Mac版是一款Mac平臺的翻譯及辭典軟件&#xff0c;Instant Translate支持90的語言互翻譯&#xff0c;通過ControlS切換語言&#xff0c;并且支持發音功能&#xff0c;并且支持自動檢測語言并進行翻譯。軟件特色Instant Translate的主要特點&#xff…

基于Zookeeper使用ZkClient實現分布式鎖

有段時間沒寫博客了&#xff0c;在整理之前寫過的一套自定義框架&#xff0c;并且整理好上傳值github上了&#xff0c;也有一些新功能還在開發&#xff0c;歡迎大家使用&#xff1a;一個好用的Http接口請求工具組件 可能今天這篇文章跟之前的比有些跳躍性&#xff0c;一下子就…

算法題學到的一些小語言細節

1.要學會用i&#xff1b;可以簡化很多代碼&#xff1a;i&#xff1b;copyFromMe(i)&#xff1b;可以寫成&#xff1a;copyFromeMe(i) 2.StringBuffer也跟列表一樣有append函數&#xff1b; 3.if語句是分支不能進行循環&#xff0c;要寫成while才能替代循環里面的判斷 4. 這里的…