成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java中的枚舉,這一篇全了,一些不為人知的干貨

開發(fā) 后端
Java枚舉,也稱作Java枚舉類型,是一種字段由一組固定常量集合組成的類型。枚舉的主要目的是加強編譯時類型的安全性。enum關(guān)鍵字是Java中的保留關(guān)鍵字。

[[387053]]

本文轉(zhuǎn)載自微信公眾號「程序新視界」,作者二師兄。轉(zhuǎn)載本文請聯(lián)系程序新視界公眾號。 

Java枚舉,也稱作Java枚舉類型,是一種字段由一組固定常量集合組成的類型。枚舉的主要目的是加強編譯時類型的安全性。enum關(guān)鍵字是Java中的保留關(guān)鍵字。

在編譯或設(shè)計時,當我們知道所有變量的可能性時,盡量使用枚舉類型。本篇文章就帶大家全面系統(tǒng)的了解枚舉的使用,以及會遇到的一些問題。

Java中的枚舉

枚舉通常是一組相關(guān)的常量集合,其他編程語言很早就開始用枚舉了,比如C++。從JDK1.5起,Java也開始支持枚舉類型。

枚舉是一種特殊的數(shù)據(jù)類型,它既是一種類(class)類型卻又比類類型多了些特殊的約束,這些約束也造就了枚舉類型的簡潔性、安全性以及便捷性。

在Java中,通過enum來聲明枚舉類型,默認繼承自java.lang.Enum。所以聲明枚舉類時無法再繼承其他類。

枚舉聲明

在生活中我們會經(jīng)常辨認方向,東南西北,它們的名稱、屬性等基本都是確定的,我們就可以將其聲明為枚舉類型:

  1. public enum Direction { 
  2.    EAST, WEST, NORTH, SOUTH; 

同樣,每周七天也可以聲明成枚舉類型:

  1. enum Day { 
  2.     MONDAY, TUESDAY, WEDNESDAY, 
  3.     THURSDAY, FRIDAY, SATURDAY, SUNDAY 

在沒有枚舉或沒使用枚舉的情況下,并不是說不可以定義變量,我們可以通過類或接口進行常量的定義:

  1. public class Day { 
  2.  
  3.     public static final int MONDAY =1; 
  4.  
  5.     public static final int TUESDAY=2; 
  6.  
  7.     public static final int WEDNESDAY=3; 
  8.  
  9.     public static final int THURSDAY=4; 
  10.  
  11.     public static final int FRIDAY=5; 
  12.  
  13.     public static final int SATURDAY=6; 
  14.  
  15.     public static final int SUNDAY=7; 
  16.  

但這樣存在許多不足,如在類型安全和使用方便性上。如果存在定義int值相同的變量,混淆的幾率還是很大的,編譯器也不會提出任何警告。因此,當能使用枚舉的時候,并不提倡這種寫法。

枚舉的底層實現(xiàn)

上面我們已經(jīng)說了,枚舉是一個特殊的類,每一個枚舉項本質(zhì)上都是枚舉類自身的實例。

因此,上面枚舉類Direction可以通過下面代碼進行示例:

  1. final class Direction extends Enum{ 
  2.     public final static Direction EAST = new Direction(); 
  3.     public final static Direction WEST = new Direction(); 
  4.     public final static Direction NORTH = new Direction(); 
  5.     public final static Direction SOUTH = new Direction(); 

首先通過javac命令對Direction進行編譯,然后通過javap命令來查看一下對應(yīng)class文件內(nèi)容:

  1. bogon:enums apple$ javap Direction.class  
  2. Compiled from "Direction.java" 
  3. public final class com.choupangxia.enums.Direction extends java.lang.Enum<com.choupangxia.enums.Direction> { 
  4.   public static final com.choupangxia.enums.Direction EAST; 
  5.   public static final com.choupangxia.enums.Direction WEST; 
  6.   public static final com.choupangxia.enums.Direction NORTH; 
  7.   public static final com.choupangxia.enums.Direction SOUTH; 
  8.   public static com.choupangxia.enums.Direction[] values(); 
  9.   public static com.choupangxia.enums.Direction valueOf(java.lang.String); 
  10.   static {}; 

可以看到,一個枚舉在經(jīng)過編譯器編譯過后,變成了一個抽象類,它繼承了java.lang.Enum;而枚舉中定義的枚舉常量,變成了相應(yīng)的public static final屬性,而且其類型就抽象類的類型,名字就是枚舉常量的名字。

枚舉使用實例

通過上面的反編譯我們可以看到,枚舉的選項本質(zhì)上就是public static final的變量,所以就把它當做這樣的變量使用即可。

  1. public class EnumExample { 
  2.     public static void main(String[] args) { 
  3.         Direction north = Direction.NORTH; 
  4.         System.out.println(north);        //Prints NORTH 
  5.     } 

枚舉的ordinal()方法

ordinal()方法用于獲取枚舉變量在枚舉類中聲明的順序,下標從0開始,與數(shù)組中的下標很相似。它的設(shè)計是用于EumSet和EnumMap復雜的基于枚舉的數(shù)據(jù)結(jié)構(gòu)使用。

  1. Direction.EAST.ordinal();     //0 
  2.   
  3. Direction.NORTH.ordinal();    //2 

需要注意的是如果枚舉項聲明的位置發(fā)生了變化,那么ordinal方法的值也隨之變化。所以,進來避免使用該方法。不然,當枚舉項比較多時,別人在中間增刪一項,會導致后續(xù)的所有順序變化。

枚舉的values()和valueOf()

values()方法可獲取枚舉類中的所有變量,并作為數(shù)組返回:

  1. Direction[] directions = Direction.values(); 
  2.   
  3. for (Direction d : directions) { 
  4.     System.out.println(d); 
  5.   
  6. //Output
  7.   
  8. EAST 
  9. WEST 
  10. NORTH 
  11. SOUTH 

values()方法是由編譯器插入到枚舉類中的static方法,而它的父類Enum中并不存在這個方法。

valueOf(String name)方法與Enum類中的valueOf方法的作用類似根據(jù)名稱獲取枚舉變量,同樣是由編譯器生成的,但更簡潔些,只需傳遞一個參數(shù)。

  1. Direction east = Direction.valueOf("EAST"); 
  2.           
  3. System.out.println(east); 
  4.   
  5. //Output
  6.   
  7. EAST 

枚舉命名約定

按照約定,枚舉屬于常量,因此采用所有字母大寫,下劃線分割的風格(UPPER_CASE)。也就是說枚舉類名與普通類約定一樣,而枚舉中的變量與靜態(tài)變量的命名規(guī)范一致。

枚舉的構(gòu)造方法

默認情況下,枚舉類是不需要構(gòu)造方法的,默認的變量就是聲明時的字符串。當然,你也可以通過自定義構(gòu)造方法,來初始化枚舉的一些狀態(tài)信息。通常情況下,我們會在構(gòu)造參數(shù)中傳入兩個參數(shù),比如,一個編碼,一個描述。

以上面的方向為例:

  1. public enum Direction { 
  2.     // enum fields 
  3.     EAST(0), WEST(180), NORTH(90), SOUTH(270); 
  4.   
  5.     // constructor 
  6.     private Direction(final int angle) { 
  7.         this.angle = angle; 
  8.     } 
  9.   
  10.     // internal state 
  11.     private int angle; 
  12.   
  13.     public int getAngle() { 
  14.         return angle; 
  15.     } 

如果我們想訪問每個方向的角度,可以通過簡單的方法調(diào)用:

  1. Direction north = Direction.NORTH; 
  2.           
  3. System.out.println(north);                      //NORTH 
  4.   
  5. System.out.println(north.getAngle());           //90 
  6.   
  7. System.out.println(Direction.NORTH.getAngle()); //90 

枚舉中的方法

枚舉就是一個特殊的類,因此也可以像普通的類一樣擁有方法和屬性。在枚舉中不僅可以聲明具體的方法,還可以聲明抽象方法。

方法的訪問權(quán)限可以是private、protected和public。可以通過這些方法返回枚舉項的值,也可以做一些內(nèi)部的私有處理。

  1. public enum Direction { 
  2.     // enum fields 
  3.     EAST, WEST, NORTH, SOUTH; 
  4.       
  5.     protected String printDirection() { 
  6.         String message = &quot;You are moving in &quot; + this + &quot; direction&quot;; 
  7.         System.out.println( message ); 
  8.         return message; 
  9.     } 

對應(yīng)方法的使用如下:

  1. Direction.NORTH.printDirection();  
  2. Direction.EAST.printDirection();  

枚舉類中還可以定義抽象的方法,但每個枚舉項中必須實現(xiàn)對應(yīng)的抽象方法:

  1. public enum Direction  
  2.     // enum fields 
  3.     EAST { 
  4.         @Override 
  5.         public String printDirection() { 
  6.             String message = &quot;You are moving in east. You will face sun in morning time.&quot;; 
  7.             return message; 
  8.         } 
  9.     }, 
  10.     WEST { 
  11.         @Override 
  12.         public String printDirection() { 
  13.             String message = &quot;You are moving in west. You will face sun in evening time.&quot;; 
  14.             return message; 
  15.         } 
  16.     }, 
  17.     NORTH { 
  18.         @Override 
  19.         public String printDirection() { 
  20.             String message = &quot;You are moving in north. You will face head in daytime.&quot;; 
  21.             return message; 
  22.         } 
  23.     }, 
  24.     SOUTH { 
  25.         @Override 
  26.         public String printDirection() { 
  27.             String message = &quot;You are moving in south. Sea ahead.&quot;; 
  28.             return message; 
  29.         } 
  30.     }; 
  31.   
  32.     public abstract String printDirection(); 

抽象方法的調(diào)用,與普通方法一樣:

  1. Direction.NORTH.printDirection();  
  2. Direction.EAST.printDirection();  

通過這種方式就可以輕而易舉地定義每個枚舉實例的不同行為方式。比如需要每個枚舉項都打印出方向的名稱,就可以定義這么一個抽象的方法。

上面的實例enum類似乎表現(xiàn)出了多態(tài)的特性,可惜的是枚舉類型的實例終究不能作為類型傳遞使用。下面的方式編譯器都無法通過:

  1. //無法通過編譯,Direction.NORTH是個實例對象 
  2.  public void text(Direction.NORTH instance){ } 

枚舉的繼承

上面已經(jīng)提到過枚舉繼承自java.lang.Enum,Enum是一個抽象類:

  1. public abstract class Enum<E extends Enum<E>> 
  2.         implements Comparable<E>, Serializable { 
  3.     // ... 

也就是說,所有的枚舉類都支持比較(Comparable)和序列化(Serializable)的特性。也正因為所有的枚舉類都繼承了Enum,所以無法再繼承其他類了,但是可以實現(xiàn)接口。

枚舉的比較

所有的枚舉默認都是Comparable和單例的,因此可以通過equals方法進行比較,甚至可以直接用雙等號“==”進行比較。

  1. Direction east = Direction.EAST; 
  2. Direction eastNew = Direction.valueOf("EAST"); 
  3.   
  4. System.out.println( east == eastNew );           //true 
  5. System.out.println( east.equals( eastNew ) );    //true 

枚舉集合:EnumSet和EnumMap

在java.util包下引入了兩個枚舉集合類:EnumSet和EnumMap。

EnumSet

EnumSet類的定義如下:

  1. public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E> 
  2.     implements Cloneable, java.io.Serializable
  3.     // ... 

EnumSet是與枚舉類型一起使用的專用Set集合,EnumSet中所有元素都必須是枚舉類型。與其他Set接口的實現(xiàn)類HashSet/TreeSet不同的是,EnumSet在內(nèi)部實現(xiàn)是位向量。

位向量是一種極為高效的位運算操作,由于直接存儲和操作都是bit,因此EnumSet空間和時間性能都十分可觀,足以媲美傳統(tǒng)上基于int的“位標志”的運算,關(guān)鍵是我們可像操作set集合一般來操作位運算。

EnumSet不允許使用null元素,試圖插入null將拋出 NullPointerException,但測試判斷是否存在null元素或移除null元素則不會拋出異常,與大多數(shù)Collection實現(xiàn)一樣,EnumSet不是線程安全的,在多線程環(huán)境下需注意數(shù)據(jù)同步問題。

使用實例:

  1. public class Test { 
  2.    public static void main(String[] args) { 
  3.      Set enumSet = EnumSet.of(  Direction.EAST, 
  4.                                 Direction.WEST, 
  5.                                 Direction.NORTH, 
  6.                                 Direction.SOUTH 
  7.                               ); 
  8.    } 
  9.  } 

EnumMap

EnumMap的聲明如下:

  1. public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V> 
  2.     implements java.io.Serializable, Cloneable 
  3. {} 

與EnumSet類似,EnumMap是一個特殊的Map,Map的Key必須是枚舉類型。EnumMap內(nèi)部是通過數(shù)組實現(xiàn)的,效率比普通的Map更高一些。EnumMap的key值不能為null,并且EnumMap也不是線程安全的。

EnumMap使用實例如下:

  1. public class Test { 
  2.   public static void main(String[] args){ 
  3.     //Keys can be only of type Direction 
  4.     Map enumMap = new EnumMap(Direction.class); 
  5.   
  6.     //Populate the Map 
  7.     enumMap.put(Direction.EAST, Direction.EAST.getAngle()); 
  8.     enumMap.put(Direction.WEST, Direction.WEST.getAngle()); 
  9.     enumMap.put(Direction.NORTH, Direction.NORTH.getAngle()); 
  10.     enumMap.put(Direction.SOUTH, Direction.SOUTH.getAngle()); 
  11.   } 

枚舉與switch

使用switch進行條件判斷時,條件參數(shù)一般只能是整型,字符型,同時也支持枚舉型,在java7后switch也對字符串進行了支持。

使用實例如下:

  1. enum Color {GREEN,RED,BLUE} 
  2.  
  3. public class EnumDemo4 { 
  4.  
  5.     public static void printName(Color color){ 
  6.         switch (color){ 
  7.             //無需使用Color進行引用 
  8.             case BLUE:  
  9.                 System.out.println("藍色"); 
  10.                 break; 
  11.             case RED: 
  12.                 System.out.println("紅色"); 
  13.                 break; 
  14.             case GREEN: 
  15.                 System.out.println("綠色"); 
  16.                 break; 
  17.         } 
  18.     } 
  19.  
  20.     public static void main(String[] args){ 
  21.         printName(Color.BLUE); 
  22.         printName(Color.RED); 
  23.         printName(Color.GREEN); 
  24.     } 

枚舉與單例

單例模式是日常使用中最常見的設(shè)計模式之一了,單例的實現(xiàn)有很多種實現(xiàn)方法(餓漢模式、懶漢模式等),這里就不再贅述,只以一個最普通的單例來做對照,進而看看基于枚舉如何來實現(xiàn)單例模式。

餓漢模式的實現(xiàn):

  1. public class Singleton { 
  2.  
  3.     private static Singleton instance = new Singleton(); 
  4.  
  5.     private Singleton() { 
  6.     } 
  7.  
  8.     public static Singleton getInstance() { 
  9.         return instance; 
  10.     } 

簡單直接,缺點是可能在還不需要時就把實例創(chuàng)建出來了,沒起到lazy loading的效果。優(yōu)點就是實現(xiàn)簡單,而且安全可靠。

這樣一個單例場景,如果通過枚舉進行實現(xiàn)如下:

  1. public enum Singleton { 
  2.  
  3.     INSTANCE; 
  4.  
  5.     public void doSomething() { 
  6.         System.out.println("doSomething"); 
  7.     } 

在effective java中說道,最佳的單例實現(xiàn)模式就是枚舉模式。利用枚舉的特性,讓JVM來幫我們保證線程安全和單一實例的問題。除此之外,寫法還特別簡單。

直接通過Singleton.INSTANCE.doSomething()的方式調(diào)用即可。方便、簡潔又安全。

小結(jié)

枚舉在日常編碼中幾乎是必不可少的,如何用好,如何用精,還需要基礎(chǔ)知識的鋪墊,本文也正是基于此帶大家從頭到尾梳理了一遍。有所收獲就點個贊吧。

 

責任編輯:武曉燕 來源: 程序新視界
相關(guān)推薦

2023-11-09 08:05:40

IDEA開發(fā)工具

2014-05-04 11:17:39

Unix命令Linux命令

2010-08-05 11:14:12

Flex優(yōu)勢

2021-11-09 07:34:34

Python函數(shù)代碼

2010-09-03 08:52:38

CSS

2021-11-03 16:48:55

Flex前端特性

2018-09-14 09:12:00

數(shù)據(jù)庫MySQL索引約束

2018-09-16 23:14:18

MySQL索引約束主鍵

2013-05-15 10:08:27

2015-11-02 14:42:12

2020-02-20 12:02:32

Python數(shù)據(jù)函數(shù)

2013-08-09 09:27:08

vCentervSphere

2010-04-19 16:09:22

Oracle控制文件

2024-05-17 13:08:46

Python代碼

2021-06-23 14:12:40

算法隊列

2014-04-11 14:22:25

前端前端知識

2011-11-08 13:41:27

蘋果siri人工智能數(shù)據(jù)中心

2011-11-15 10:25:56

IBMWindows

2014-08-18 10:44:31

斯諾登

2010-09-06 14:19:54

CSS
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 美女黄视频网站 | 一区二区免费在线视频 | 仙人掌旅馆在线观看 | 久久久久久成人 | 97国产爽爽爽久久久 | 99在线免费观看视频 | www.国产精| 亚洲91视频 | 乱码av午夜噜噜噜噜动漫 | av片在线免费看 | 激情av在线 | av国产精品毛片一区二区小说 | 精品国产久 | 国产免费一区二区三区 | 日本不卡一区 | wwwxxx日本在线观看 | 日本久久精品 | a级片在线观看 | 精品国产91久久久久久 | 午夜国产一级片 | 久久国 | 亚洲黄色一区二区三区 | 免费成人av | 国产精品综合色区在线观看 | 欧美自拍网站 | 国产美女黄色片 | 男女视频在线观看免费 | 桃花av在线 | 精品国产乱码久久久久久丨区2区 | 国产色在线| 亚洲欧美bt | 国产在线a | 超碰av免费| 91在线视频免费观看 | 一区二区三区影院 | 水蜜桃久久夜色精品一区 | 日本三级做a全过程在线观看 | 日本电影韩国电影免费观看 | 国产一区二区在线观看视频 | 国产激情小视频 | 成人精品在线视频 |