Java中的枚举

187 阅读3分钟

在实习过程中,公司项目上用到枚举来表示请求处理的状态,返回结果,而自己以前也只是有简单的做过几个Demo,没有经常使用,所以当时使用的时候也是比较生疏。因此想找时间把这个枚举系统的复习整理一遍,方便以后查阅。

一、定义

枚举类型是指一组固定的常量组成合法的类型。Java中由关键字enum来定义一个枚举类型。

public enum Season {
    SPRING(1,"春天"),
    SUMMER(2,"夏天"),
    AUTUMN(3,"秋天"),
    WINER(4,"冬天");
 }

二、特点

  • 使用关键字enum
  • 一串允许的值
  • 可以单独定义在一个文件中,也可以嵌在其他java类中
  • 枚举可以实现一个或者多个接口
  • 可以定义新的变量
  • 可以定义新的方法
  • 可以定义根据具体枚举值而相异的类

三、常用的用法

用法一:声明常量

public enum Season {
    SPRING,SUMMER,AUTUMN,WINER;
 }

用法二:与switch搭配使用

   public void change(Season season) {
        switch (season) {
            case SPRING:
                System.out.println("春天来了!");
                break;
            case SUMMER:
                System.out.println("夏天来了!");
                break;
            case AUTUMN:
                System.out.println("秋天来了!");
                break;
            case WINER:
                System.out.println("冬天来了!");
                break;
            default:
                System.out.println("不知道什么季节呢!");
                break;
        }
    }

用法三:在枚举中添加新的方法

   /**
     * 根据传入的code值获取对应的季节
     */
    public Season getSeasonByCode(int code){
        for(Season s : Season.values()){
            if(s.getCode() == code){
                return s;
            }
        }
        return null;
    }

用法四:实现接口,根据具体枚举值而生成相异的类

这种用法是以前自己没有使用过的,十分推荐。

public interface Behaviour {
    void print();
    String sayHello();
}
public enum Season implements Behaviour {

    SPRING(1, "春天") {
        @Override
        public void print() {
            System.out.println("春天来了!");
        }

        @Override
        public String sayHello() {
            return "春天";
        }
    },
    SUMMER(2, "夏天") {
        @Override
        public void print() {
            System.out.println("夏天来了!");
        }

        @Override
        public String sayHello() {
            return "夏天";
        }
    },
    AUTUMN(3, "秋天") {
        @Override
        public void print() {
            System.out.println("秋天来了!");
        }

        @Override
        public String sayHello() {
            return "秋天";
        }
    },
    WINER(4, "冬天") {
        @Override
        public void print() {
            System.out.println("冬天来了!");
        }

        @Override
        public String sayHello() {
            return "冬天";
        }
    };
//其他代码省略

这种方式可以用来优化代码中的if/else判断,调用的时候也十分简单。

    public String judge(String name){
        return Season.valueOf(name).sayHello();
    }

三、深入探讨Java枚举

枚举是如何保证线程安全的

要探讨这个问题,首先我们必须先定义一个枚举

public enum t {
    SPRING,SUMMER,AUTUMN,WINTER;
}

反编译后的代码

public final class T extends Enum
{
    private T(String s, int i)
    {
        super(s, i);
    }
    public static T[] values()
    {
        T at[];
        int i;
        T at1[];
        System.arraycopy(at = ENUM$VALUES, 0, at1 = new T[i = at.length], 0, i);
        return at1;
    }

    public static T valueOf(String s)
    {
        return (T)Enum.valueOf(demo/T, s);
    }

    public static final T SPRING;
    public static final T SUMMER;
    public static final T AUTUMN;
    public static final T WINTER;
    private static final T ENUM$VALUES[];
    static
    {
        SPRING = new T("SPRING", 0);
        SUMMER = new T("SUMMER", 1);
        AUTUMN = new T("AUTUMN", 2);
        WINTER = new T("WINTER", 3);
        ENUM$VALUES = (new T[] {
            SPRING, SUMMER, AUTUMN, WINTER
        });
    }
}

接下来,我们就来分析一下反编译后的这些代码,来分析枚举是如何保证线程安全性问题的。

首先在public final class T extends Enum中,我们可以看到T是继承Enum,而且被final修饰的,所以T不能被其他类继承。当我们使用enum来定义一个枚举时,编译器会帮我们创建一个final类型的类继承于Enum,所以枚举类型不能被继承。 其次,我们可以看到SPRING,SUMMER,AUTUMN,WINTER都被static和final两个关键字修饰,属于静态的且不可变的变量,而且用了静态代码块来初始化这四个变量,使用static修饰和使用静态代码块来初始化说明什么?

有了解过Java类的加载机制的朋友会知道,static类型的属性会在类被加载之后被初始化,当一个Java类第一次被真正使用到的时候静态资源被初始化,Java类的加载和初始化过程都是线程安全的。所以,创建一个enum类型是线程安全的。

结语

文章部分内容转载H神的博客,十分推荐他写的文章!其他详细深入的内容请看原文。 www.hollischuang.com/archives/19…