<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          教妹學(xué)Java 第 45 講:枚舉

          共 9076字,需瀏覽 19分鐘

           ·

          2021-07-18 16:28

          “今天我們來學(xué)習(xí)枚舉吧,三妹!”我說,“同學(xué)讓你去她家玩了兩天,感覺怎么樣呀?”

          “心情放松了不少。”三妹說,“可以開始學(xué) Java 了,二哥。”

          “OK。”

          “枚舉(enum),是 Java 1.5 時引入的關(guān)鍵字,它表示一種特殊類型的類,繼承自 java.lang.Enum。”

          “我們來新建一個枚舉 PlayerType。”

          public enum PlayerType {
              TENNIS,
              FOOTBALL,
              BASKETBALL
          }

          “二哥,我沒看到有繼承關(guān)系呀!”

          “別著急,看一下反編譯后的字節(jié)碼,你就明白了。”

          public final class PlayerType extends Enum
          {

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

              public static PlayerType valueOf(String name)
              
          {
                  return (PlayerType)Enum.valueOf(com/cmower/baeldung/enum1/PlayerType, name);
              }

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

              public static final PlayerType TENNIS;
              public static final PlayerType FOOTBALL;
              public static final PlayerType BASKETBALL;
              private static final PlayerType $VALUES[];

              static 
              {
                  TENNIS = new PlayerType("TENNIS"0);
                  FOOTBALL = new PlayerType("FOOTBALL"1);
                  BASKETBALL = new PlayerType("BASKETBALL"2);
                  $VALUES = (new PlayerType[] {
                      TENNIS, FOOTBALL, BASKETBALL
                  });
              }
          }

          “看到?jīng)]?Java 編譯器幫我們做了很多隱式的工作,不然手寫一個枚舉就沒那么省心省事了。”

          • 要繼承 Enum 類;
          • 要寫構(gòu)造方法;
          • 要聲明靜態(tài)變量和數(shù)組;
          • 要用 static 塊來初始化靜態(tài)變量和數(shù)組;
          • 要提供靜態(tài)方法,比如說 values() 和  valueOf(String name)

          “確實,作為開發(fā)者,我們的代碼量減少了,枚舉看起來簡潔明了。”三妹說。

          “既然枚舉是一種特殊的類,那它其實是可以定義在一個類的內(nèi)部的,這樣它的作用域就可以限定于這個外部類中使用。”我說。

          public class Player {
              private PlayerType type;
              public enum PlayerType {
                  TENNIS,
                  FOOTBALL,
                  BASKETBALL
              }
              
              public boolean isBasketballPlayer() {
                return getType() == PlayerType.BASKETBALL;
              }

              public PlayerType getType() {
                  return type;
              }

              public void setType(PlayerType type) {
                  this.type = type;
              }
          }

          PlayerType 就相當(dāng)于 Player 的內(nèi)部類。

          由于枚舉是 final 的,所以可以確保在 Java 虛擬機(jī)中僅有一個常量對象,基于這個原因,我們可以使用“==”運算符來比較兩個枚舉是否相等,參照 isBasketballPlayer() 方法。

          “那為什么不使用 equals() 方法判斷呢?”三妹問。

          if(player.getType().equals(Player.PlayerType.BASKETBALL)){};

          “我來給你解釋下。”

          “==”運算符比較的時候,如果兩個對象都為 null,并不會發(fā)生 NullPointerException,而 equals() 方法則會。

          另外, “==”運算符會在編譯時進(jìn)行檢查,如果兩側(cè)的類型不匹配,會提示錯誤,而 equals() 方法則不會。

          “枚舉還可用于 switch 語句,和基本數(shù)據(jù)類型的用法一致。”我說。

          switch (playerType) {
                  case TENNIS:
                      return "網(wǎng)球運動員費德勒";
                  case FOOTBALL:
                      return "足球運動員C羅";
                  case BASKETBALL:
                      return "籃球運動員詹姆斯";
                  case UNKNOWN:
                      throw new IllegalArgumentException("未知");
                  default:
                      throw new IllegalArgumentException(
                              "運動員類型: " + playerType);

              }

          “如果枚舉中需要包含更多信息的話,可以為其添加一些字段,比如下面示例中的 name,此時需要為枚舉添加一個帶參的構(gòu)造方法,這樣就可以在定義枚舉時添加對應(yīng)的名稱了。”我繼續(xù)說。

          public enum PlayerType {
              TENNIS("網(wǎng)球"),
              FOOTBALL("足球"),
              BASKETBALL("籃球");

              private String name;

              PlayerType(String name) {
                  this.name = name;
              }
          }

          “get 了吧,三妹?”

          “嗯,比較好理解。”

          “那接下來,我就來說點不一樣的。”

          “來吧,我準(zhǔn)備好了。”

          “EnumSet 是一個專門針對枚舉類型的 Set 接口(后面會講)的實現(xiàn)類,它是處理枚舉類型數(shù)據(jù)的一把利器,非常高效。”我說,“從名字上就可以看得出,EnumSet 不僅和 Set 有關(guān)系,和枚舉也有關(guān)系。”

          “因為 EnumSet 是一個抽象類,所以創(chuàng)建 EnumSet 時不能使用 new 關(guān)鍵字。不過,EnumSet 提供了很多有用的靜態(tài)工廠方法。”

          “來看下面這個例子,我們使用 noneOf() 靜態(tài)工廠方法創(chuàng)建了一個空的 PlayerType 類型的 EnumSet;使用 allOf() 靜態(tài)工廠方法創(chuàng)建了一個包含所有 PlayerType 類型的 EnumSet。”

          public class EnumSetTest {
              public enum PlayerType {
                  TENNIS,
                  FOOTBALL,
                  BASKETBALL
              }

              public static void main(String[] args) {
                  EnumSet<PlayerType> enumSetNone = EnumSet.noneOf(PlayerType.class);
                  System.out.println(enumSetNone);

                  EnumSet<PlayerType> enumSetAll = EnumSet.allOf(PlayerType.class);
                  System.out.println(enumSetAll);
              }
          }

          “來看一下輸出結(jié)果。”

          []
          [TENNIS, FOOTBALL, BASKETBALL]

          有了 EnumSet 后,就可以使用 Set 的一些方法了,見下圖。

          “除了 EnumSet,還有 EnumMap,是一個專門針對枚舉類型的 Map 接口的實現(xiàn)類,它可以將枚舉常量作為鍵來使用。EnumMap 的效率比 HashMap 還要高,可以直接通過數(shù)組下標(biāo)(枚舉的 ordinal 值)訪問到元素。”

          “和 EnumSet 不同,EnumMap 不是一個抽象類,所以創(chuàng)建 EnumMap 時可以使用 new 關(guān)鍵字。”

          EnumMap<PlayerType, String> enumMap = new EnumMap<>(PlayerType.class);

          有了 EnumMap 對象后就可以使用 Map 的一些方法了,見下圖。

          和 HashMap(后面會講)的使用方法大致相同,來看下面的例子。

          EnumMap<PlayerType, String> enumMap = new EnumMap<>(PlayerType.class);
          enumMap.put(PlayerType.BASKETBALL,"籃球運動員");
          enumMap.put(PlayerType.FOOTBALL,"足球運動員");
          enumMap.put(PlayerType.TENNIS,"網(wǎng)球運動員");
          System.out.println(enumMap);

          System.out.println(enumMap.get(PlayerType.BASKETBALL));
          System.out.println(enumMap.containsKey(PlayerType.BASKETBALL));
          System.out.println(enumMap.remove(PlayerType.BASKETBALL));

          “來看一下輸出結(jié)果。”

          {TENNIS=網(wǎng)球運動員, FOOTBALL=足球運動員, BASKETBALL=籃球運動員}
          籃球運動員
          true
          籃球運動員

          “除了以上這些,《Effective Java》這本書里還提到了一點,如果要實現(xiàn)單例的話,最好使用枚舉的方式。”我說。

          “等等二哥,單例是什么?”三妹沒等我往下說,就連忙問道。

          “單例(Singleton)用來保證一個類僅有一個對象,并提供一個訪問它的全局訪問點,在一個進(jìn)程中。因為這個類只有一個對象,所以就不能再使用 new 關(guān)鍵字來創(chuàng)建新的對象了。”

          “Java 標(biāo)準(zhǔn)庫有一些類就是單例,比如說 Runtime 這個類。”

          Runtime runtime = Runtime.getRuntime();

          “Runtime 類可以用來獲取 Java 程序運行時的環(huán)境。”

          “關(guān)于單例,懂了些吧?”我問三妹。

          “噢噢噢噢。”三妹點了點頭。

          “通常情況下,實現(xiàn)單例并非易事,來看下面這種寫法。”

          public class Singleton {  
              private volatile static Singleton singleton; 
              private Singleton (){}  
              public static Singleton getSingleton() {  
              if (singleton == null) {
                  synchronized (Singleton.class
                  if (singleton == null) {  
                      singleton = new Singleton(); 
                  }  
                  }  
              }  
              return singleton;  
              }  
          }

          “要用到 volatile、synchronized 關(guān)鍵字等等,但枚舉的出現(xiàn),讓代碼量減少到極致。”

          public enum EasySingleton{
              INSTANCE;
          }

          “就這?”三妹睜大了眼睛。

          “對啊,枚舉默認(rèn)實現(xiàn)了 Serializable 接口,因此 Java 虛擬機(jī)可以保證該類為單例,這與傳統(tǒng)的實現(xiàn)方式不大相同。傳統(tǒng)方式中,我們必須確保單例在反序列化期間不能創(chuàng)建任何新實例。”我說。

          “好了,關(guān)于枚舉就講這么多吧,三妹,你把這些代碼都手敲一遍吧!”

          “好勒,這就安排。二哥,你去休息吧。”

          “嗯嗯。”講了這么多,必須跑去抽煙機(jī)那里安排一根華子了。


          PS:點擊「閱讀原文」可直達(dá)《教妹學(xué)Java》專欄的在線閱讀地址,可以收藏夾伺候一波了!

          瀏覽 21
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  午夜影院操 | 操熟女逼| 午夜福利视频性爱 | 天天操天天摸天天碰 | 精品国产制服丝袜高跟 |