亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

扒一扒 Java 中的枚舉類(lèi)型

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

前言

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

枚舉類(lèi)更加直觀(guān),類(lèi)型安全。使用常量會(huì)有以下幾個(gè)缺陷:

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

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

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

1. 枚舉的定義

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

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

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

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

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á)到定義的, 我們?cè)谑褂脮r(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)行起來(lái)也沒(méi)問(wèn)題。 但是, 我們就如同上面第二種調(diào)用方式一樣, 其實(shí)我們的方向就在 4 種范圍之內(nèi),但在調(diào)用的時(shí)候傳入不是方向的一個(gè) int 類(lèi)型的數(shù)據(jù), 編譯器是不會(huì)檢查出來(lái)的。

1.2 枚舉方法

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

定義

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

測(cè)試

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

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

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

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

1.3 定義總結(jié)

以剛剛的代碼為例

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

2 枚舉的本質(zhì)

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

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

// final:無(wú)法繼承
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)用父類(lèi)的 valueOf 方法 
 public static DirectionEnum valueOf(String name)
 {
 return (DirectionEnum)Enum.valueOf(cn/homejim/java/lang/DirectionEnum, name);
 }
 // 私有化構(gòu)造函數(shù), 正常情況下無(wú)法從外部進(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
 });
 }
}

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

2.1 繼承 java.lang.Enum

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

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

可以看出來(lái), java.lang.Enum 有如下幾個(gè)特征

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

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

2.2 final 類(lèi)型

final 修飾, 說(shuō)明枚舉類(lèi)型是無(wú)法進(jìn)行繼承的

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

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

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

2.5 添加了 $values[] 變量及兩個(gè)方法

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

3 枚舉的一般使用

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

3.1 類(lèi)本身的方法

從前面我的分析, 我們得出, 類(lèi)本身有兩個(gè)方法, 是編譯時(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)

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

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

3.2 繼承的方法

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

3.2.1 ordinal()

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

在基于枚舉的復(fù)雜數(shù)據(jù)結(jié)構(gòu) EnumSet和EnumMap 中會(huì)用到該函數(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;
 }

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

 @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()

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

3.2.4 getDeclaringClass()

獲取對(duì)應(yīng)枚舉類(lèi)型的 Class 對(duì)象

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

2.3.5 equals

判斷指定對(duì)象與枚舉常量是否相同

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

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

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

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

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

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

我們給每個(gè)方向加上一個(gè)角度

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

測(cè)試

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

4.2 添加自定義的方法

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

4.2.1 自定義具體方法

我們?cè)诿杜e類(lèi)型內(nèi)部加入如下具體方法

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

測(cè)試

 @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 在枚舉中定義抽象方法

在枚舉類(lèi)型中, 也是可以定義 abstract 方法的

我們?cè)贒irectinEnum中定義如下的抽象方法

abstract String onDirection();

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

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

測(cè)試

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

輸出

EAST direction 1
NORTH direction 333

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

4.3 覆蓋父類(lèi)方法

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

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

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

但Java是可以實(shí)現(xiàn)多個(gè)接口的, 因此 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");
 }
 // 其他代碼
}

測(cè)試

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

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

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

public enum Singlton {
 INSTANCE;

 public void doOtherThing() {
  
 }
}

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

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

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

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

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

總結(jié)

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

相關(guān)文章

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

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

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

    Java中的CountDownLatch簡(jiǎn)單理解

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

    Java的sort的排序及使用詳解

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

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

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

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

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

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

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

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

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

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

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

    Java多線(xiàn)程-線(xiàn)程的同步與鎖的問(wèn)題

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

    java中TestNG使用教程詳解

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

最新評(píng)論