枚举类的使用和理解enmu

 

原始的接口定义常量

public interface IConstants {

    String MON = "Mon";

    String TUE = "Tue";

    String WED = "Wed";

    String THU = "Thu";

    String FRI = "Fri";

    String SAT = "Sat";

    String SUN = "Sun";

}

语法(定义)

    创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类(java.lang.Enum 是一个抽象类)。枚举类型符合通用模式 Class Enum<E extends Enum<E>>,而 E 表示枚举类型的名称。枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal) 构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序。

package com.hmw.test;

扫描二维码关注公众号,回复: 3937421 查看本文章

/**

 * 枚举测试类

 */

public enum EnumTest {

    MON, TUE, WED, THU, FRI, SAT, SUN;

}

这段代码实际上调用了7次 Enum(String name, int ordinal):

new Enum<EnumTest>("MON",0);

new Enum<EnumTest>("TUE",1);

new Enum<EnumTest>("WED",2);

    ... ...

遍历、switch 等常用操作

对enum进行遍历和switch的操作示例代码:

public class Test {

    public static void main(String[] args) {

        for (EnumTest e : EnumTest.values()) {

            System.out.println(e.toString());

        }

         

        System.out.println("----------------我是分隔线------------------");

         

        EnumTest test = EnumTest.TUE;

        switch (test) {

        case MON:

            System.out.println("今天是星期一");

            break;

        case TUE:

            System.out.println("今天是星期二");

            break;

        // ... ...

        default:

            System.out.println(test);

            break;

        }

    }

}

输出结果:

MON

TUE

WED

THU

FRI

SAT

SUN

----------------我是分隔线------------------

今天是星期二

enum 对象的常用方法介绍

int compareTo(E o) 
          比较此枚举与指定对象的顺序。

Class<E> getDeclaringClass() 
          返回与此枚举常量的枚举类型相对应的 Class 对象。

String name() 
          返回此枚举常量的名称,在其枚举声明中对其进行声明。

int ordinal() 
          返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。

String toString()

           返回枚举常量的名称,它包含在声明中。

static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) 

反编译解析:

 public enum ColorEnum {

    RED,BLUE,GREEN

 }

  通过工具解析class后获得的源代码(

 public final class ColorEnum extends Enum
 {

    //返回存储枚举实例的数组的副本。values()方法通常用于foreach循环遍历枚举常量。
    public static ColorEnum[] values()
    {
        return (ColorEnum[])$VALUES.clone();
    }
    //根据实例名获取实例
    public static ColorEnum valueOf(String s)
    {
        return (ColorEnum)Enum.valueOf(ColorEnum, s);
    }

    //私有构造方法,这里调用了父类的构造方法,其中参数s对应了常量名,参数i代表枚举的一个顺序(这个顺序与枚举的声明顺序对应,用于oridinal()方法返回顺序值)
    private ColorEnum(String s, int i)
    {
        super(s, i);
    }

    //我们定义的枚举在这里声明了三个 ColorEnum的常量对象引用,对象的实例化在static静态块中
    public static final ColorEnum RED;
    public static final ColorEnum BLUE;
    public static final ColorEnum GREEN;
    //将所有枚举的实例存放在数组中
    private static final ColorEnum $VALUES[];

    static 
    {
        RED = new ColorEnum("RED", 0);
        BLUE = new ColorEnum("BLUE", 1);
        GREEN = new ColorEnum("GREEN", 2);
        //将所有枚举的实例存放在数组中
        $VALUES = (new ColorEnum[] {
            RED, BLUE, GREEN
        });
    }
}

给 enum 自定义属性和方法

public enum ColorEnum {
    RED("red","红色"),GREEN("green","绿色"),BLUE("blue","蓝色");
    //防止字段值被修改,增加的字段也统一final表示常量
    private final String key;
    private final String value;
    
    private ColorEnum(String key,String value){
        this.key = key;
        this.value = value;
    }
    //根据key获取枚举
    public static ColorEnum getEnumByKey(String key){
        if(null == key){
            return null;
        }
        for(ColorEnum temp:ColorEnum.values()){
            if(temp.getKey().equals(key)){
                return temp;
            }
        }
        return null;
    }
    public String getKey() {
        return key;
    }
    public String getValue() {
        return value;
    }
}
反编译结果:
public final class ColorEnum extends Enum
{

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

    public static ColorEnum valueOf(String s)
    {
        return (ColorEnum)Enum.valueOf(ColorEnum, s);
    }

    //构造方法在原基础上加上我们新增的两个形参
    private ColorEnum(String s, int i, String s1, String s2)
    {
        super(s, i);
        key = s1;
        value = s2;
    }

    //自定义方法,通过key值获得对应的枚举对象
    public static ColorEnum getEnumByKey(String s)
    {
        if(null == s)
            return null;
        ColorEnum acolorenum[] = values();
        int i = acolorenum.length;
        for(int j = 0; j < i; j++)
        {
            ColorEnum colorenum = acolorenum[j];
            if(colorenum.getKey().equals(s))
                return colorenum;
        }

        return null;
    }

    public String getKey()
    {
        return key;
    }

    public String getValue()
    {
        return value;
    }

    public static final ColorEnum RED;
    public static final ColorEnum GREEN;
    public static final ColorEnum BLUE;
    //我们自定义的两个字段
    private final String key;
    private final String value;
    private static final ColorEnum $VALUES[];

    static 
    {
        RED = new ColorEnum("RED", 0, "red", "\u7EFE\u3223\u58CA");
        GREEN = new ColorEnum("GREEN", 1, "green", "\u7F01\u80EF\u58CA");
        BLUE = new ColorEnum("BLUE", 2, "blue", "\u9483\u6FCA\u58CA");
        $VALUES = (new ColorEnum[] {
            RED, GREEN, BLUE
        });
    }
EnumSet,EnumMap 的应用

public class Test {

    public static void main(String[] args) {

        // EnumSet的使用

        EnumSet<EnumTest> weekSet = EnumSet.allOf(EnumTest.class);

        for (EnumTest day : weekSet) {

            System.out.println(day);

        }

        // EnumMap的使用

        EnumMap<EnumTest, String> weekMap = new EnumMap(EnumTest.class);

        weekMap.put(EnumTest.MON, "星期一");

        weekMap.put(EnumTest.TUE, "星期二");

        // ... ...

        for (Iterator<Entry<EnumTest, String>> iter = weekMap.entrySet().iterator(); iter.hasNext();) {

            Entry<EnumTest, String> entry = iter.next();

            System.out.println(entry.getKey().name() + ":" + entry.getValue());

        }

    }

}

原理分析

        enum 的语法结构尽管和 class 的语法不一样,但是经过编译器编译之后产生的是一个class文件。该class文件经过反编译可以看到实际上是生成了一个类,该类继承了java.lang.Enum<E>。EnumTest 经过反编译(javap com.hmw.test.EnumTest 命令)之后得到的内容如下:

public class com.hmw.test.EnumTest extends java.lang.Enum{

    public static final com.hmw.test.EnumTest MON;

    public static final com.hmw.test.EnumTest TUE;

    public static final com.hmw.test.EnumTest WED;

    public static final com.hmw.test.EnumTest THU;

    public static final com.hmw.test.EnumTest FRI;

    public static final com.hmw.test.EnumTest SAT;

    public static final com.hmw.test.EnumTest SUN;

    static {};

    public int getValue();

    public boolean isRest();

    public static com.hmw.test.EnumTest[] values();

    public static com.hmw.test.EnumTest valueOf(java.lang.String);

    com.hmw.test.EnumTest(java.lang.String, int, int, com.hmw.test.EnumTest);

}

所以,实际上 enum 就是一个 class,只不过 java 编译器帮我们做了语法的解析和编译而已。

总结

1、转变观念

最重要的是把enum看成和class和interface同等地位就好很容易理解EnumSet和EnumMap。

    可以把 enum 看成是一个普通的 class,它们都可以定义一些属性和方法,不同之处是:enum 不能使用 extends 关键字继承其他类,因为 enum 已经继承了 java.lang.Enum(java是单一继承)

2.枚举的好处以及与常量类的区别


  1)枚举型可以直接与数据库打交道,我通常使用varchar类型存储,对应的是枚举的常量名。(数据库中好像也有枚举类型,不过也没用过)

  2) switch语句支持枚举型,当switch使用int、String类型时,由于值的不稳定性往往会有越界的现象,对于这个的处理往往只能通过if条件筛选以及default模块来处理。而使用枚举型后,在编译期间限定类型,不允许发生越界的情况

  3) 当你使用常量类时,往往得通过equals去判断两者是否相等,使用枚举的话由于常量值地址唯一,可以用==直接对比,性能会有提高

  4) 常量类编译时,是直接把常量的值编译到类的二进制代码里,常量的值在升级中变化后,需要重新编译引用常量的类,因为里面存的是旧值。枚举类编译时,没有把常量值编译到代码里,即使常量的值发生变化,也不会影响引用常量的类。

  5)枚举类编译后默认为final class,不允许继承可防止被子类修改。常量类可被继承修改、增加字段等,容易导致父类的不兼容。

  总结:常量的定义在开发中是必不可少的,虽然无论是通过常量类定义常量还是枚举定义常量都可以满足常量定义的需求。但个人建议最好是使用枚举类型。

猜你喜欢

转载自blog.csdn.net/yaoyaowudi123/article/details/82498584
今日推荐