今天看啥  ›  专栏  ›  胖先森

JavaSE基础:枚举类型

胖先森  · 掘金  · Java  · 2018-03-03 11:35

JavaSE基础:枚举类型

枚举类型(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());
        }
    }
}




原文地址:访问原文地址
快照地址: 访问文章快照