JavaSE基礎:列舉型別

胖先森發表於2018-03-03

列舉型別(Enum)

在C語言中存在一個列舉型別,通過此型別可以限制一個內容的取值範圍,但是在JDK1.5之前,Java中並並不存在列舉的型別,所以很多之間已經習慣了使用列舉型別操作的開發人員就感覺很不適應,為了解決這個問題(或者說吸引部分客戶),所以在JDK1.5之後就加入了列舉型別。

我個人而言,本身就是從Java學起,其實是否使用列舉型別看自己的習慣就可以,對於我來說有的時候列舉型別就有點雞肋的感覺,我可以使用別的方式實現類似的列舉。

情景模式說明,我們平時可能要獲取星期幾,但是我們獲取的是陣列1-7的形式,那麼我們就需要對起進行處理,實現程式碼如下。

1.簡單程式實現列舉功能

請注意關鍵的問題,我們需要限制取值的範圍!

package com.shxt.demo01;

public class Week {
    //定義七個星期的物件
    public static final Week SUNDAY = new Week("星期日");
    public static final Week MONDAY = new Week("星期一");
    public static final Week TUESDAY = new Week("星期二");
    public static final Week WEDNESDAY = new Week("星期三");
    public static final Week THURSDAY = new Week("星期四");
    public static final Week FRIDAY = new Week("星期五");
    public static final Week SATURDAY = new Week("星期六");

    private String date;

    //請注意這裡使用的私有建構函式,無法在外部進行例項化操作
    private Week(String date){
        this.date = date;
    }

    public String getDate() {
        return date;
    }

    public void setDate(String date) {
        this.date = date;
    }

    //獲取日期陣列,從固定的星期中獲取資料
    public static Week getInstance(int week){
        switch (week){
            case 1:
                return SUNDAY;
            case 2:
                return MONDAY;
            case 3:
                return TUESDAY;
            case 4:
                return WEDNESDAY;
            case 5:
                return THURSDAY;
            case 6:
                return FRIDAY;
            case 7:
                return SATURDAY;
            default:
                return null;//錯誤的數值

        }
    }
}

複製程式碼

測試程式碼:

package com.shxt.demo01;

import java.util.Calendar;

public class WeekTest {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        //System.out.println(calendar.get(Calendar.DAY_OF_WEEK));
        Week week = Week.getInstance(calendar.get(Calendar.DAY_OF_WEEK));
        if (week!=null){
            System.out.println(week.getDate());
        }
    }
}
複製程式碼

程式碼說明:

以上程式將Week類中的構造方法進行私有化處理,之後在類中準備了若干個例項化物件,以後如果要獲取Week類的例項,只能使用MONDAY...SUNDAY7個物件,這樣就有效的限制了物件的取值範圍

以上使用的Week物件的指定範圍,我們發現是通過一個個常量對每個物件進行了編號。也就是一個個物件就相當於用常量進行了標識,所以按照這個思路我們也可以直接使用一個介面定義一組常量範圍(這種方法個人使用較少)

package com.shxt.demo02;

public interface Week {
    //自動補全public static final
    int SUNDAY = 1;
    int MONDAY = 2;
    int TUESDAY = 3;
    int WEDNESDAY = 4;
    int THURSDAY = 5;
    int FRIDAY = 6;
    int SATURDAY = 7;
}
複製程式碼

但是通過介面的方式的列舉會存在問題,會存在結果操作不正確的問題

package com.shxt.demo02;

public class WeekTest {
    public static void main(String[] args) {
        System.out.println(Week.SATURDAY+Week.FRIDAY);//星期的資料相加,沒有該結果
    }
}
複製程式碼

使用我們這種方式,使用者想知道到底有多少星期可以使用(假設你不知道),則實現的程式碼會比較複雜,還有就是犧牲也比較大,所以在JDK1.5之後就專門解決了類似的問題。

2.定義列舉型別

在JDK1.5之後,引入了一個新的關鍵字型別——enum,可以直接定義列舉型別,語法格式如下

public enum 列舉型別名稱{
    列舉物件1,列舉物件2,列舉物件3,...,列舉物件N
}
複製程式碼

示例1:定義一個列舉型別

package com.shxt.demo03;
public enum Week {
    SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY;
}

複製程式碼

示例2:取出列舉內容

package com.shxt.demo03;

public class Test01 {
    public static void main(String[] args) {
        Week w = Week.MONDAY;//得到MONDAY
        System.out.println(w);
    }
}
/*
執行結果為:MONDAY
*/
複製程式碼

這個結果感覺並沒有什麼卵用,我們需要一步步來,使用此方式好處可以避免之前使用介面方式的問題

package com.shxt.demo03;

public class Test02 {
    public static void main(String[] args) {
        System.out.println(Week.MONDAY+Week.FRIDAY);//錯誤
    }
}
複製程式碼

列舉型別的資料也可以使用“列舉.values()”的形式,將全部的列舉型別變為物件陣列的形式,之後直接使用foreach進行操作。

示例3:使用foreach輸出列舉內容

package com.shxt.demo03;

public class Test03 {
    public static void main(String[] args) {
        Week[] weeks = Week.values();
        for (Week w : weeks){
            System.out.println(w);
        }
    }
}
複製程式碼

示例4:使用switch進行判斷

現在的一切都是簡單介紹,後面還有更加具體的介紹

package com.shxt.demo03;

public class Test04 {
    public static void main(String[] args) {
        Week[] weeks = Week.values();
        for (Week w : weeks){
            print(w);
        }
    }

    public static void print(Week week){
        switch (week){
            case SUNDAY:
                System.out.println("星期日");
                break;
            case MONDAY:
                System.out.println("星期一");
                break;
            case TUESDAY:
                System.out.println("星期二");
                break;
            case WEDNESDAY:
                System.out.println("星期三");
                break;
            case THURSDAY:
                System.out.println("星期四");
                break;
            case FRIDAY:
                System.out.println("星期五");
                break;
            case SATURDAY:
                System.out.println("星期六");
                break;
            default:
                System.out.println("什麼鬼???");
                break;

        }
    }
}

複製程式碼

上述過程介紹的列舉的使用在實際開發中應用是非常少的,作為開發人員必須要進一步的深入瞭解列舉型別

3.進一步深入列舉型別

使用enum關鍵字可以定義一個列舉型別,實際上此關鍵字筆試的是java.lang.Enum類,使用enum宣告的列舉型別就相當於定義一個類,而此類預設繼承了java.lang.Enum類

public abstract class Enum<E extends Enum<E>> 
extends Object 
implements Comparable<E>, Serializable
複製程式碼
編號 方法名稱 型別 描述
1 protected Enum(String name,int ordinal) 構造 接收列舉的名稱和列舉常量建立列舉物件
2 protected final Object clone()
throws CloneNotSupportedException
普通 克隆列舉物件
3 public final int compareTo(E o) 普通 物件比較
4 public final boolean equals(Object other) 普通 比較兩個列舉物件
5 public final int hashCode() 普通 返回列舉常量的雜湊碼
6 public final String name() 普通 返回此列舉的名稱
7 public final int ordinal() 普通 返回列舉常量的序數
8 public static <T extends Enum> T
valueOf(Class enumType, String name)
普通 返回帶指定名稱的指定列舉型別的列舉常量

示例1:獲取列舉的資訊

package com.shxt.demo03;

public enum Week {
    SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY;
}
複製程式碼
package com.shxt.demo03;

public class Test05 {
    public static void main(String[] args) {
        for (Week w : Week.values()) {
            System.out.println(w.ordinal()+"->"+w.name());
        }
    }
}
/** 執行結果:
         0->SUNDAY
         1->MONDAY
         2->TUESDAY
         3->WEDNESDAY
         4->THURSDAY
         5->FRIDAY
         6->SATURDAY
 */
複製程式碼

示例2:通過構造方法為屬性賦值

每個列舉類中都有其指定的若干個物件,當然,每個列舉可以包含多個屬性,必須在enum例項序列的最後新增一個分號,Java 要求必須先定義 enum 例項.

package com.shxt.demo04;

public enum Week {
    SUNDAY("星期日",7),MONDAY("星期一",1),TUESDAY("星期二",2),
    WEDNESDAY("星期三",3),THURSDAY("星期四",4),FRIDAY("星期五",5),SATURDAY("星期六",6);

    private String name;
    private int index;
    //構造方法
    private Week(String name,int index){
        this.name = name;
        this.index = index;
    }

    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;
    }
}
複製程式碼

Week列舉類中增加了兩個屬性name和index,並通過私有構造方法設定name和index屬性的內容,因為Week中已經明確定義了兩個引數的構造方法,所以列舉內容必須要呼叫該構造方法.

package com.shxt.demo04;

public class Test05 {
    public static void main(String[] args) {
        for (Week w : Week.values()) {
            System.out.println("序號:"+w.ordinal()+"  列舉名稱:"+w.name()+"  屬性name值:"+w.getName()+"  屬性index值:"+w.getIndex());
        }
    }
}
/**
    執行結果為:
         序號:0  列舉名稱:SUNDAY  屬性name值:星期日  屬性index值:7
         序號:1  列舉名稱:MONDAY  屬性name值:星期一  屬性index值:1
         序號:2  列舉名稱:TUESDAY  屬性name值:星期二  屬性index值:2
         序號:3  列舉名稱:WEDNESDAY  屬性name值:星期三  屬性index值:3
         序號:4  列舉名稱:THURSDAY  屬性name值:星期四  屬性index值:4
         序號:5  列舉名稱:FRIDAY  屬性name值:星期五  屬性index值:5
         序號:6  列舉名稱:SATURDAY  屬性name值:星期六  屬性index值:6
 */
複製程式碼

示例3:覆蓋列舉方法toString

package com.shxt.demo05;

public enum Week {
    SUNDAY("星期日",7),MONDAY("星期一",1),TUESDAY("星期二",2),
    WEDNESDAY("星期三",3),THURSDAY("星期四",4),FRIDAY("星期五",5),SATURDAY("星期六",6);

    private String name;
    private int index;
    //構造方法
    private Week(String name, int index){
        this.name = name;
        this.index = index;
    }

    @Override
    public String toString() {
        return "Week{" +
                "name='" + name + '\'' +
                ", index=" + index +
                '}';
    }
}

複製程式碼
package com.shxt.demo05;

public class Test05 {
    public static void main(String[] args) {
        for (Week w : Week.values()) {
            System.out.println(w);
        }
    }
}
/**
    執行結果為:
         Week{name='星期日', index=7}
         Week{name='星期一', index=1}
         Week{name='星期二', index=2}
         Week{name='星期三', index=3}
         Week{name='星期四', index=4}
         Week{name='星期五', index=5}
         Week{name='星期六', index=6}
 */
複製程式碼

示例4:使用比較器

在Enum類中已經實現好了Comparable介面,所以列舉類的內容本身是可以進行排序的,只是測試一下結果,在類集的時候我們介紹過TreeSet可以直接進行排序,排序規則是根據Comparable介面完成的

package com.shxt.demo06;

public enum Week {
    SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY;
}
複製程式碼
import java.util.TreeSet;

public class Test01 {
    public static void main(String[] args) {
        Set<Week> weekSet = new TreeSet<>();
        //亂存資料
        weekSet.add(Week.FRIDAY);
        weekSet.add(Week.MONDAY);
        weekSet.add(Week.THURSDAY);
        weekSet.add(Week.WEDNESDAY);
        weekSet.add(Week.TUESDAY);
        weekSet.add(Week.SATURDAY);
        weekSet.add(Week.SUNDAY);
        for (Week w:weekSet){
            System.out.println(w.ordinal()+"-->"+w.name());
        }
    }
}
複製程式碼

迭代出的資料順序是根據ordinal屬性進行排序的.

4.類集對列舉的支援

(1)EnumMap

EnumMap是Map介面中的子類,所以本身還是以Map的形式進行操作,key=>value

package com.shxt.demo07;

public enum  Color {
    RED,YELLOW,BLUE;
}
複製程式碼
package com.shxt.demo07;

import java.util.EnumMap;
import java.util.Map;

public class EnumMapTest {
    public static void main(String[] args) {
        Map<Color,String> map = new EnumMap<Color, String>(Color.class);
        map.put(Color.RED,"紅色");
        map.put(Color.YELLOW,"黃色");
        map.put(Color.BLUE,"藍色");

        System.out.println("**********輸出全部的列舉內容和其對應的值************");
        for(Color c : Color.values()){
            System.out.println(c.name()+"  map中的value:"+map.get(c));
        }

        System.out.println("**********獲取全部的鍵值***************************");
        for (Color c : map.keySet()){
            System.out.println("KEY="+c.name());
        }
        System.out.println("**********獲取全部的內容***************************");
        for (String s : map.values()){
            System.out.println("Value="+s);
        }

    }
}

複製程式碼

上述的程式碼的應用場景我不太清楚,有清楚的請留言告知

(2)EnumSet

EnumSet是Set介面的子類,所以裡面的內容是無法重複.使用EnumSet時不能直接使用關鍵字new為其進行例項化,而是使用本類提供的靜態方法

序號 方法名稱 型別 描述
1 public static <E extends Enum<E>>
EnumSet<E> allOf(Class<E> elementType)
普通 將列舉中的全部內容設定到EnumSet中
2 public static <E extends Enum<E>>
EnumSet<E> of(E first,E...rest)
普通 建立一個包含列舉指定內容的EnumSet物件
3 public static <E extends Enum<E>>
EnumSet<E> copyOf(Collection<E> c)
普通 建立一個從指定Collection中指定的EnumSet物件
4 public static <E extends Enum<E>>
EnumSet<E> complementOf(EnumSet<E> s)
普通 建立一個其元素型別與指定列舉 set 相同的列舉
set,最初包含指定 set 中所不 包含的此型別的所有元素。
5 public static <E extends Enum<E>>
EnumSet<E> noneOf(Class<E> e)
普通 建立一個可以接收指定型別的空集合

示例1:將全部的列舉設定到EnumSet集合中

package com.shxt.demo08;

import java.util.EnumSet;

enum  Color {
    RED,YELLOW,BLUE;
}

public class DenumSetDemo01 {

    public static void main(String[] args) {
        EnumSet<Color> set = EnumSet.allOf(Color.class);//將列舉的全部資料設定到EnumSet物件中

        for (Color c : set){
            System.out.println(c);
        }

    }

}
複製程式碼

示例2:設定一個列舉資料到EnumSet結合中

package com.shxt.demo08;

import java.util.EnumSet;

enum  Color {
    RED,YELLOW,BLUE;
}

public class DenumSetDemo02 {

    public static void main(String[] args) {
        EnumSet<Color> set = EnumSet.of(Color.YELLOW);//設定一個列舉內容

        for (Color c : set){
            System.out.println(c);
        }

    }

}

複製程式碼

示例3:只能放入指定的列舉型別的集合

package com.shxt.demo08;

import java.util.EnumSet;

enum  Color {
    RED,YELLOW,BLUE;
}

public class DenumSetDemo03 {

    public static void main(String[] args) {
        EnumSet<Color> set = EnumSet.noneOf(Color.class);//建立一個可以鍵入Color型別的物件
        set.add(Color.YELLOW);
        set.add(Color.BLUE);

        for (Color c : set){
            System.out.println(c);
        }

    }

}
複製程式碼

其他的方法就不做測試了,感覺也沒有什麼實際的用處,這裡就省略...見諒

5.讓列舉實現一個介面

列舉類也可以實現一個介面,但是因為介面中存在的都是抽線方法,所以列舉類中的每個物件必須分別實現介面中的抽象方法

package com.shxt.demo09;

interface Print{
    String getColor();
}

enum Color implements Print{
    RED{
        @Override
        public String getColor() {
            return "紅色";
        }
    },YELLOW{
        @Override
        public String getColor() {
            return "黃色";
        }
    },BLUE{
        @Override
        public String getColor() {
            return "藍色";
        }
    };
}

public class InterfaceEnumDemo01 {
    public static void main(String[] args) {
        for (Color c : Color.values()){
            System.out.println(c.getColor());
        }
    }
}

複製程式碼

或者這樣寫也是可以的

package com.shxt.demo10;

interface Print{
    String getColor();
}

enum Color implements Print {
   RED("紅色"),YELLOW("黃色"),BLUE("藍色");
   private String name;
   private Color(String name){
       this.name = name;
   }

    @Override
    public String getColor() {
        return this.name;
    }
}

public class InterfaceEnumDemo01 {
    public static void main(String[] args) {
        for (Color c : Color.values()){
            System.out.println(c.getColor());
        }
    }
}

複製程式碼

6.在列舉類中定義抽象方法

package com.shxt.demo11;


enum Color {
   RED("紅色") {
       @Override
       public String getColor() {
           return "紅紅=>"+this.name;
       }
   },YELLOW("黃色") {
        @Override
        public String getColor() {
            return "黃黃=>"+this.name;
        }
    },BLUE("藍色") {
        @Override
        public String getColor() {
            return "藍藍=>"+this.name;
        }
    };
   protected String name;
   private Color(String name){
       this.name = name;
   }


    public abstract String getColor() ;
}

public class AbstractEnumDemo01 {
    public static void main(String[] args) {
        for (Color c : Color.values()){
            System.out.println(c.getColor());
        }
    }
}

複製程式碼

相關文章