Java核心类——枚举类

在Java中,我们可以通过static final来定义常量。例如定义周一到周日:

public class weekday {
    public static final int SUN = 0;
    public static final int MON = 1;
    public static final int TUE = 2;
    public static final int WED =3;
    public static final int THU = 4;
    public static final int FRI = 5;
    public static final int SAT = 6;
}

使用常量的时候,可以这么引用:

if (day == Weekday.SAT || day == Weekday.SUN) {}

当然也可以将常量定义为字符串类型。

无论是int常量还是String常量,使用这些常量来表示一组枚举的时候,
有一个严重的问题就是,编译器无法检查每个值得合理性。比如:

if (weekday == 6 || weekday == 7) {
    if (tasks == weekday.MON) {
        // TODO    
    }
}

上面代码存在两个问题:
(1)weekday定义得常量范围是0-6,并不包含7,编译器无法检测不在枚举中得int值
(2)定义的常量仍可以于其他变量比较,但其用途并非是枚举星期值

为了让编译器能自动检查某个值在枚举的集合内,并且不同用途的枚举需要不同的类型来标记:

enum Weekday {
    SUN,MON,TUE,WED,THU,FRI,SAT;
}

public class catchExample2 {
    public static void main(String[] args) throws Exception {
        Weekday day = Weekday.SUN;
        if (day == Weekday.SAT || day == Weekday.SUN) {
            System.out.println("At home");
        } else {
            System.out.println("At office");
        }
    }
}

枚举类是通过关键字enum实现的,我们只需要一次列出枚举的常量名。
和int定义的常量相比,使用enum定义枚举有如下好处:
  (1)enum常量本身带有类型信息,即Weekday.SUN类型是Weekday,编译器会自动检查类型错误。
  (2)不可能引用到非枚举的值,因为无法通过编译。
  (3)不同类型的枚举不能相互比较或者赋值,因为类型不符。
这使得编译器可以在编译期自动检查所有可能潜在的错误。

使用enum定义的枚举是一种引用类型。
前面我们讲到,引用类型比较,要使用equals()方法,如果使用==,它比较两个引用类型的变量是否是同一个对象。
因此,引用类型比较,要始终使用equals()方法,但enum类型可以例外。
因为enum类型的每个常量在JVM中只有一个唯一实例,所以可以直接使用==比较。

enum定义的枚举类,与class有什么区别了?
enum是就是一个class,只是被单独定义了。主要区别有以下几点:
  (1)定义的enum类型总是继承自java.lang.Enum,且无法被继承。
  (2)只能定义出enum的实例,无法通过new操作符创建enum对象。
  (3)定义的每个实例都是引用类型的唯一实例
  (4)可以将enum类型用于switch语句。

例如,我们定义的color类:

public enum Color {
    RED, GREEN, BLUE;
}

编译器编译的class大概就是这样:

public final class Color extends Enum { // 继承自Enum,标记为final class
    // 每个实例均为全局唯一:
    public static final Color RED = new Color();
    public static final Color GREEN = new Color();
    public static final Color BLUE = new Color();
    // private构造方法,确保外部无法调用new操作符:
    private Color() {}
}

所以,编译后的enum类和普通class并没有任何区别。
但是我们自己无法按定义普通class那样来定义enum关键字,这是Java语法规定。

因为enum是一个class,每个枚举的值都是class实例,因此,这些实例有一些方法:
name():返回常量名
  String s = Weekday.SUN.name();
ordianl():返回定义的常量的顺序,从0开始技术。
  int n = Weekday.MON.ordinal();
改变枚举常量定义的顺序就会导致ordinal()返回值。

上面创建的枚举依旧存在一个问题,如果我们不小心修改枚举的顺序,
那么其所代表的ordinal的返回值也会被修改。
因为我们可以稍微优化一下,给每个枚举常量添加字段:

package com.imooc.iexecption;

enum Weekday {
    SUN(0), MON(1),TUE(2),WED(3),THU(4),FRI(5),SAT(6);

    public final int dayValue;

    private Weekday(int dayValue) {
        this.dayValue = dayValue;
    }
}

public class catchExample2 {
    public static void main(String[] args) throws Exception {
        Weekday day = Weekday.SUN;
        if (day.dayValue == 6 || day.dayValue == 0) {
            System.out.println("At home");
        } else {
            System.out.println("At office");
        }
    }
}

这样,我们就不用过多的关注顺序的问题。
默认情况下,对枚举常量调用toString()会返回和name()一样的字符串,
但是,toString()可以被覆写,而name则不行,我们可以给weekday添加toString()方法。

package com.imooc.iexecption;

enum Weekday {
    SUN(0,"星期日"),
    MON(1,"星期一"),
    TUE(2,"星期二"),
    WED(3,"星期三"),
    THU(4,"星期四"),
    FRI(5,"星期五"),
    SAT(6,"星期六");

    public final int dayValue;
    private final String chinese;

    private Weekday(int dayValue, String chinese) {
        this.dayValue = dayValue;
        this.chinese = chinese;
    }
    @Override  //不允许被覆写,也可以直接调用name()
    public String toString() {
        return this.chinese;
    }
}

public class catchExample2 {
    public static void main(String[] args) throws Exception {
        Weekday day = Weekday.SUN;
        if (day.dayValue == 6 || day.dayValue == 0) {
            System.out.println("Today is " + day + " At home");
        } else {
            System.out.println("Today is" + day + "At office");
        }
    }
}

覆写toString()的目的是在输出时更有可读性。

枚举可以应用在switch语句中。因为枚举天生举有类型信息和有限个枚举常量,
所以比int、String类型更适合用在switch语句中。

package com.imooc.iexecption;

enum Weekday {
    SUN, MON, TUE, WED, THU, FRI, SAT;
}

public class catchExample2 {
    public static void main(String[] args) throws Exception {
        Weekday day = Weekday.SUN;
        switch (day) {
            case SUN:
            case MON:
            case THU:
                System.out.println("Today is " + day + " At home");
                break;
            case WED:
            case TUE:
                System.out.println("Today is " + day + " At office");
                break;
            case FRI:
            case SAT:
            default:
                throw new RuntimeException("cannot process" + day);
        }
    }
}

  加上default语句,可以在漏写某个枚举常量时自动报错。

猜你喜欢

转载自www.cnblogs.com/yangmingxianshen/p/12501447.html
今日推荐