欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

扒一扒 Java 中的枚舉類型

 更新時(shí)間:2018年12月03日 16:33:30   作者:阿進(jìn)的寫字臺  
這篇文章主要給大家介紹了Java中枚舉類型的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

在 Java 中, 枚舉, 也稱為枚舉類型, 其是一種特殊的數(shù)據(jù)類型, 它使得變量能夠稱為一組預(yù)定義的常量。 其目的是強(qiáng)制編譯時(shí)類型安全。

枚舉類更加直觀,類型安全。使用常量會有以下幾個缺陷:

1. 類型不安全。若一個方法中要求傳入季節(jié)這個參數(shù),用常量的話,形參就是int類型,開發(fā)者傳入任意類型的int類型值就行,但是如果是枚舉類型的話,就只能傳入枚舉類中包含的對象。

2. 沒有命名空間。開發(fā)者要在命名的時(shí)候以SEASON_開頭,這樣另外一個開發(fā)者再看這段代碼的時(shí)候,才知道這四個常量分別代表季節(jié)。

因此, 在 Java 中, enum 是保留的關(guān)鍵字。

1. 枚舉的定義

在 Java 是在 JDK 1.4 時(shí)決定引入的, 其在 JDK 1.5 發(fā)布時(shí)正式發(fā)布的。

舉一個簡單的例子:以日常生活中的方向來定義, 因?yàn)槠涿Q, 方位等都是確定, 一提到大家就都知道。

1.1 傳統(tǒng)的非枚舉方法

如果不使用枚舉, 我們可能會這樣子定義

public class Direction {
 public static final int EAST = 0;

 public static final int WEST = 1;

 public static final int SOUTH = 2;

 public static final int NORTH = 3;
 
}

以上的定義也是可以達(dá)到定義的, 我們在使用時(shí)

 @Test
 public void testDirection() {
 System.out.println(getDirectionName(Direction.EAST));
 System.out.println(getDirectionName(5));// 也可以這樣調(diào)用
 }

 public String getDirectionName(int type) {
 switch (type) {
  case Direction.EAST:
  return "EAST";
  case Direction.WEST:
  return "WEST";
  case Direction.SOUTH:
  return "SOUTH";
  case Direction.NORTH:
  return "NORTH";
  default:
  return "UNKNOW";
 }
 }

運(yùn)行起來也沒問題。 但是, 我們就如同上面第二種調(diào)用方式一樣, 其實(shí)我們的方向就在 4 種范圍之內(nèi),但在調(diào)用的時(shí)候傳入不是方向的一個 int 類型的數(shù)據(jù), 編譯器是不會檢查出來的。

1.2 枚舉方法

我們使用枚舉來實(shí)現(xiàn)上面的功能

定義

public enum DirectionEnum {
 EAST, WEST, NORTH, SOUTH
}

測試

 @Test
 public void testDirectionEnum() {
 System.out.println(getDirectionName(DirectionEnum.EAST));
 // System.out.println(getDirectionName(5));// 編譯錯誤
 }

 public String getDirectionName(DirectionEnum direction) {
 switch (direction) {
  case EAST:
  return "EAST";
  case WEST:
  return "WEST";
  case SOUTH:
  return "SOUTH";
  case NORTH:
  return "NORTH";
  default:
  return "UNKNOW";
 }
 }

以上只是一個舉的例子, 其實(shí), 枚舉中可以很方便的獲取自己的名稱。

通過使用枚舉, 我們可以很方便的限制了傳入的參數(shù), 如果傳入的參數(shù)不是我們指定的類型, 則就發(fā)生錯誤。

1.3 定義總結(jié)

以剛剛的代碼為例

public enum DirectionEnum {
 EAST, WEST, NORTH, SOUTH
}
  • 枚舉類型的定義跟類一樣, 只是需要將 class 替換為 enum
  • 枚舉名稱與類的名稱遵循一樣的慣例來定義
  • 枚舉值由于是常量, 一般推薦全部是大寫字母
  • 多個枚舉值之間使用逗號分隔開
  • 最好是在編譯或設(shè)計(jì)時(shí)就知道值的所有類型, 比如上面的方向, 當(dāng)然后面也可以增加

2 枚舉的本質(zhì)

枚舉在編譯時(shí), 編譯器會將其編譯為 Java 中 java.lang.Enum 的子類。

我們將上面的 DirectionEnum 進(jìn)行反編譯, 可以獲得如下的代碼:

// final:無法繼承
public final class DirectionEnum extends Enum
{
 // 在之前定義的實(shí)例
 public static final DirectionEnum EAST;
 public static final DirectionEnum WEST;
 public static final DirectionEnum NORTH;
 public static final DirectionEnum SOUTH;
 private static final DirectionEnum $VALUES[];
 
 // 編譯器添加的 values() 方法
 public static DirectionEnum[] values()
 {
 return (DirectionEnum[])$VALUES.clone();
 }
 // 編譯器添加的 valueOf 方法, 調(diào)用父類的 valueOf 方法 
 public static DirectionEnum valueOf(String name)
 {
 return (DirectionEnum)Enum.valueOf(cn/homejim/java/lang/DirectionEnum, name);
 }
 // 私有化構(gòu)造函數(shù), 正常情況下無法從外部進(jìn)行初始化
 private DirectionEnum(String s, int i)
 {
 super(s, i);
 }
 
 // 靜態(tài)代碼塊初始化枚舉實(shí)例
 static 
 {
 EAST = new DirectionEnum("EAST", 0);
 WEST = new DirectionEnum("WEST", 1);
 NORTH = new DirectionEnum("NORTH", 2);
 SOUTH = new DirectionEnum("SOUTH", 3);
 $VALUES = (new DirectionEnum[] {
  EAST, WEST, NORTH, SOUTH
 });
 }
}

通過以上反編譯的代碼, 可以發(fā)現(xiàn)以下幾個特點(diǎn)

2.1 繼承 java.lang.Enum

通過以上的反編譯, 我們知道了, java.lang.Enum 是所有枚舉類型的基類。查看其定義

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

可以看出來, java.lang.Enum 有如下幾個特征

  • 抽象類, 無法實(shí)例化
  • 實(shí)現(xiàn)了 Comparable 接口, 可以進(jìn)行比較
  • 實(shí)現(xiàn)了 Serializable 接口, 可進(jìn)行序列化

因此, 相對應(yīng)的, 枚舉類型也可以進(jìn)行比較和序列化

2.2 final 類型

final 修飾, 說明枚舉類型是無法進(jìn)行繼承的

2.3 枚舉常量本身就是該類的實(shí)例對象

可以看到, 我們定義的常量, 在類內(nèi)部是以實(shí)例對象存在的, 并使用靜態(tài)代碼塊進(jìn)行了實(shí)例化。

2.4 構(gòu)造函數(shù)私有化
不能像正常的類一樣, 從外部 new 一個對象出來。

2.5 添加了 $values[] 變量及兩個方法

  • $values[]: 一個類型為枚舉類本身的數(shù)組, 存儲了所有的示例類型
  • values() : 獲取以上所有實(shí)例變量的克隆值
  • valueOf(): 通過該方法可以通過名稱獲得對應(yīng)的枚舉常量

3 枚舉的一般使用

枚舉默認(rèn)是有幾個方法的

3.1 類本身的方法

從前面我的分析, 我們得出, 類本身有兩個方法, 是編譯時(shí)添加的

3.1.1 values()

先看其源碼

 public static DirectionEnum[] values() {
 return (DirectionEnum[])$VALUES.clone();
 }

返回的是枚舉常量的克隆數(shù)組。

使用示例

 @Test
 public void testValus() {
 DirectionEnum[] values = DirectionEnum.values();
 for (DirectionEnum direction:
  values) {
  System.out.println(direction);
 }
 }

輸出

EAST
WEST
NORTH
SOUTH

3.1.2 valueOf(String)

該方法通過字符串獲取對應(yīng)的枚舉常量

 @Test
 public void testValueOf() {
 DirectionEnum east = DirectionEnum.valueOf("EAST");
 System.out.println(east.ordinal());// 輸出0
 }

3.2 繼承的方法

因?yàn)槊杜e類型繼承于 java.lang.Enum, 因此除了該類的私有方法, 其他方法都是可以使用的。

3.2.1 ordinal()

該方法返回的是枚舉實(shí)例的在定義時(shí)的順序, 類似于數(shù)組, 第一個實(shí)例該方法的返回值為 0。

在基于枚舉的復(fù)雜數(shù)據(jù)結(jié)構(gòu) EnumSet和EnumMap 中會用到該函數(shù)。

 @Test
 public void testOrdinal() {
 System.out.println(DirectionEnum.EAST.ordinal());// 輸出 0
 System.out.println(DirectionEnum.NORTH.ordinal()); // 輸出 2
 }

3.2.2 compareTo()

該方法時(shí)實(shí)現(xiàn)的 Comparable 接口的, 其實(shí)現(xiàn)如下

 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;
 }

首先, 需要枚舉類型是同一種類型, 然后比較他們的 ordinal 來得出大于、小于還是等于。

 @Test
 public void testCompareTo() {
 System.out.println(DirectionEnum.EAST.compareTo(DirectionEnum.EAST) == 0);// true
 System.out.println(DirectionEnum.WEST.compareTo(DirectionEnum.EAST) > 0); // true
 System.out.println(DirectionEnum.WEST.compareTo(DirectionEnum.SOUTH) < 0); // true
 }

3.2.3 name() 和 toString()

該兩個方法都是返回枚舉常量的名稱。 但是, name() 方法時(shí) final 類型, 是不能被覆蓋的! 而 toString 可以被覆蓋。

3.2.4 getDeclaringClass()

獲取對應(yīng)枚舉類型的 Class 對象

@Test
public void testGetDeclaringClass() {
 System.out.println(DirectionEnum.WEST.getDeclaringClass());
 // 輸出 class cn.homejim.java.lang.DirectionEnum
}

2.3.5 equals

判斷指定對象與枚舉常量是否相同

 @Test
 public void testEquals() {
 System.out.println(DirectionEnum.WEST.equals(DirectionEnum.EAST)); // false
 System.out.println(DirectionEnum.WEST.equals(DirectionEnum.WEST)); // true
 }

4 枚舉類型進(jìn)階

枚舉類型通過反編譯我們知道, 其實(shí)也是一個類(只不過這個類比較特殊, 加了一些限制), 那么, 在類上能做的一些事情對其也是可以做的。 但是, 個別的可能會有限制(方向吧, 編譯器會提醒我們的)

4.1 自定義構(gòu)造函數(shù)

首先, 定義的構(gòu)造函數(shù)可以是 private, 或不加修飾符

自定義構(gòu)造函數(shù)

我們給每個方向加上一個角度

public enum DirectionEnum {
 EAST(0), WEST(180), NORTH(90), SOUTH(270);

 private int angle;

 DirectionEnum(int angle) {
 this.angle = angle;
 }

 public int getAngle() {
 return angle;
 }
}

測試

 @Test
 public void testConstructor() {
 System.out.println(DirectionEnum.WEST.getAngle()); // 180
 System.out.println(DirectionEnum.EAST.getAngle()); // 0
 }

4.2 添加自定義的方法

以上的 getAngle 就是我們添加的自定義的方法

4.2.1 自定義具體方法

我們在枚舉類型內(nèi)部加入如下具體方法

 protected void move() {
 System.out.println("You are moving to " + this + " direction");
 }

測試

 @Test
 public void testConcreteMethod() {
  DirectionEnum.WEST.move();
  DirectionEnum.NORTH.move();
 }

輸出

You are moving to WEST direction
You are moving to NORTH direction

4.2.2 在枚舉中定義抽象方法

在枚舉類型中, 也是可以定義 abstract 方法的

我們在DirectinEnum中定義如下的抽象方法

abstract String onDirection();

定義完之后, 發(fā)現(xiàn)編譯器報(bào)錯了, 說我們需要實(shí)現(xiàn)這個方法

按要求實(shí)現(xiàn)

測試

 @Test
 public void testAbstractMethod() {
  System.out.println(DirectionEnum.EAST.onDirection());
  System.out.println(DirectionEnum.SOUTH.onDirection());
 }

輸出

EAST direction 1
NORTH direction 333

也就是說抽象方法會強(qiáng)制要求每一個枚舉常量自己實(shí)現(xiàn)該方法。 通過提供不同的實(shí)現(xiàn)來達(dá)到不同的目的。

4.3 覆蓋父類方法

在父類 java.lang.Enum 中, 也就只有 toString() 是沒有使用 final 修飾啦, 要覆蓋也只能覆蓋該方法。 該方法的覆蓋相信大家很熟悉, 在此就不做過多的講解啦

4.4 實(shí)現(xiàn)接口

因?yàn)镴ava是單繼承的, 因此, Java中的枚舉因?yàn)橐呀?jīng)繼承了 java.lang.Enum, 因此不能再繼承其他的類。

但Java是可以實(shí)現(xiàn)多個接口的, 因此 Java 中的枚舉也可以實(shí)現(xiàn)接口。

定義接口

public interface TestInterface {
 void doSomeThing();
}

實(shí)現(xiàn)接口

public enum DirectionEnum implements TestInterface{
 // 其他代碼
 public void doSomeThing() {
  System.out.println("doSomeThing Implement");
 }
 // 其他代碼
}

測試

 @Test
 public void testImplement() {
  DirectionEnum.WEST.doSomeThing(); // 輸出 doSomeThing Implement
 }

5 使用枚舉實(shí)現(xiàn)單例

該方法是在 《Effective Java》 提出的

public enum Singlton {
 INSTANCE;

 public void doOtherThing() {
  
 }
}

使用枚舉的方式, 保證了序列化機(jī)制, 絕對防止多次序列化問題, 保證了線程的安全, 保證了單例。 同時(shí), 防止了反射的問題。

該方法無論是創(chuàng)建還是調(diào)用, 都是很簡單。 《Effective Java》 對此的評價(jià):

單元素的枚舉類型已經(jīng)成為實(shí)現(xiàn)Singleton的最佳方法。

6 枚舉相關(guān)的集合類

java.util.EnumSet 和 java.util.EnumMap, 在此不進(jìn)行過多的講述了。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Java遞歸遍歷樹形結(jié)構(gòu)的實(shí)現(xiàn)代碼

    Java遞歸遍歷樹形結(jié)構(gòu)的實(shí)現(xiàn)代碼

    這篇文章主要介紹了Java遞歸遍歷樹形結(jié)構(gòu)的相關(guān)資料,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2016-03-03
  • Java中的CountDownLatch簡單理解

    Java中的CountDownLatch簡單理解

    這篇文章主要介紹了Java中的CountDownLatch簡單理解,CountDownLatch是一個同步工具類,用來攜調(diào)多個線程之間的同步,它是是使用一個計(jì)數(shù)器進(jìn)行實(shí)現(xiàn)的,計(jì)數(shù)器初始值為線程數(shù)量,需要的朋友可以參考下
    2024-01-01
  • Java的sort的排序及使用詳解

    Java的sort的排序及使用詳解

    這篇文章主要為大家詳細(xì)介紹了Java的sort的排序及使用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下 ,希望您能夠多多關(guān)注
    2022-02-02
  • 詳解關(guān)于eclipse中使用jdk15對應(yīng)javafx15的配置問題總結(jié)

    詳解關(guān)于eclipse中使用jdk15對應(yīng)javafx15的配置問題總結(jié)

    這篇文章主要介紹了詳解關(guān)于eclipse中使用jdk15對應(yīng)javafx15的配置問題總結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 關(guān)于Spring Cloud健康檢查的陷阱

    關(guān)于Spring Cloud健康檢查的陷阱

    這篇文章主要介紹了關(guān)于Spring Cloud健康檢查的陷阱,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • java實(shí)現(xiàn)推箱子小游戲

    java實(shí)現(xiàn)推箱子小游戲

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)推箱子小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • Springboot如何根據(jù)實(shí)體類生成數(shù)據(jù)庫表

    Springboot如何根據(jù)實(shí)體類生成數(shù)據(jù)庫表

    這篇文章主要介紹了Springboot如何根據(jù)實(shí)體類生成數(shù)據(jù)庫表的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot集成gRPC微服務(wù)工程搭建實(shí)踐的方法

    SpringBoot集成gRPC微服務(wù)工程搭建實(shí)踐的方法

    這篇文章主要介紹了SpringBoot集成gRPC微服務(wù)工程搭建實(shí)踐的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • Java多線程-線程的同步與鎖的問題

    Java多線程-線程的同步與鎖的問題

    線程的同步是為了防止多個線程訪問一個數(shù)據(jù)對象時(shí),對數(shù)據(jù)造成的破壞。本篇文章主要介紹了Java多線程-線程的同步與鎖的問題,有興趣的可以了解一下。
    2016-11-11
  • java中TestNG使用教程詳解

    java中TestNG使用教程詳解

    TestNG是Java中的一個測試框架, 類似于JUnit 和NUnit, 本文主要介紹了java中TestNG使用教程詳解,具有一定的參考價(jià)值,感興趣的可以了解一下
    2021-12-12

最新評論