Enum

Posted howlet

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Enum相关的知识,希望对你有一定的参考价值。



最近Github上项目中看到了用枚举来列举错误码,听就是听过枚举,但没实际用过,所以来学习下


1. Enum

Enum是一种受限制的类,编译时IDE会为enum生成一个相关的类,这个类继承自 java.lang.Enum,且具有自己的方法


1.1 先来看看Enum类源码

public abstract class Enum< E extends Enum<E> > implements Comparable<E>, Serializable {

    // 枚举实例的名字
    private final String name;
    public final String name() {
        return name;
    }

  	// 枚举声明的次序
    private final int ordinal;
    public final int ordinal() {
        return ordinal;
    }

    // 构造方法,只能编译器调用,说明枚举有名字和次序
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

    // 应该调用这个来获取名字
    public String toString() {
        return name;
    }

    // 因为JVM会确保只有一个实例,所以可用==来比较
    public final boolean equals(Object other) {
        return this == other;
    }

    // 重写:比较的是声明次序
    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }

    // 返回枚举实例的数组
    public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }
}

1.2 简单实例

public enum Animal {
    DOG, CAT, BIRD, LION, ELEPHANT;
}

1.3 简单实例的反编译源码

// 声明为final类
final class Animal extends Enum{
    
    // 编译器生成的两个方法:values、valueOf
    public static Animal[] values(){
        return (Animal[])$VALUES.clone();  // 克隆一个
    }
   
    public static Animal valueOf(String s){
        return (Animal)Enum.valueOf(com/howl/enumn/Animal, s);
    }
    
    // 私有构造方法
    private Animal(String s, int i){
        super(s, i);
    }
    
    // 我们写的变量,本质为实例变量
    public static final Animal DOG;
    public static final Animal CAT;
    public static final Animal BIRD;
    public static final Animal LION;
    public static final Animal ELEPHANT;
    private static final Animal $VALUES[];

    // 实例化
    static {    
        DOG = new Animal("DOG", 0);
        CAT = new Animal("CAT", 1);
        BIRD = new Animal("BIRD", 2);
        LION = new Animal("LION", 3);
        ELEPHANT = new Animal("ELEPHANT", 4);
        $VALUES = (new Animal[] {
            DOG, CAT, BIRD, LION, ELEPHANT
        });
    }
}

各实例会在静态代码块被赋值,根据JVM的加载过程,我们知道Enum的创建过程是线程安全的


至此大家应该对Enum有稍微的了解,那么再来看看枚举的常用方法


1.4 常用方法

返回值 方法名 解释
Enum[] values() 返回enum实例数组
Enum valueOf() 返回指定名字的enum实例
int compareTo() 实现了该接口,可比较
int ordinal() 返回声明次序
String name() 返回实例名
Enum getDeclaringClass() 返回enum类型
boolean equals() 比较是否同一对象
  • JVM保证枚举类型仅一个常量实例,所以也可用 == 来比较enum实例

1.5 简单使用

如果枚举不添加任何方法,枚举值默认为从0开始的有序数值

public class EnumDemo {

    // 约定值大写,序号默认从0开始
    enum Animal {
        DOG, CAT, BIRD, LION, ELEPHANT;
    }

    public static void main(String[] args) {
        
        // 遍历枚举值
        for (Animal value : Animal.values()) {
            System.out.println(value.ordinal() + ":" + value);
        }

        // 其方法
        Animal dog = Animal.DOG;
        System.out.println(dog.name());
        System.out.println(dog.getDeclaringClass());
        System.out.println(Animal.valueOf("DOG") == dog);
    }

}
0:DOG
1:CAT
2:BIRD
3:LION
4:ELEPHANT

DOG
class enumm.EnumDemo$Animal
true




2. 自定义方法、变量

编译器会为枚举类自动继承Enum,所以无法再使用继承了,其余方面和普通类没什么区别


注意:

  • 若为枚举定义方法,那么必须先声明实例,且在最后一个实例后加分号
  • Java中不允许使用赋值符号 = 为枚举常量赋值,但可自定义方法来赋值
  • 父类方法只有toString没有被声明为final,那么只有toString才能被重写

public enum  Animal {

    // 声明实例
    DOG(1,"狗"),
    CAT(2,"猫"),
    BIRD(4,"鸟"),
    LION(8,"狮子"),
    ELEPHANT(16,"大象");

    // 私有属性
    private int num;
    private String name;
    
    // 获取内部私有属性的接口
    public int getNum() {
        return num;
    }
    public String getName() {
        return name;
    }
    
    // 构造方法只能声明为private,或者不声明
    private Animal(int num,String name){
        this.num = num;
        this.name = name;
    }

    // 可以重写toString来代替get属性的方法
    @Override
    public String toString() {
        return "Animal{" +
                "num=" + num +
                ", name=‘" + name + ‘‘‘ +
                ‘}‘;
    }

    // 静态方法
    public static void main(String[] args) {
        for (Animal value : Animal.values()){
            System.out.println(value.toString());
        }
    }
}
Animal{num=1, name=‘狗‘}
Animal{num=2, name=‘猫‘}
Animal{num=4, name=‘鸟‘}
Animal{num=8, name=‘狮子‘}
Animal{num=16, name=‘大象‘}




3. 应用

枚举可以将常量组织起来,统一进行管理,而且安全性有保证,那么其常见于错误码的同一管理

public enum ErrorCodeEnum {

    SUCCESS(0000,"成功"),
    PARAM_TYPE_ERROR(1000,"参数类型错误"),
    USER_NOT_LOGIN(2000,"用户未登录"),
    SERVER_ERROR(3000,"服务端错误");

    private Integer code;
    private String msg;

    public Integer getCode(){
        return code;
    }
    public String getMsg(){
        return msg;
    }

    private ErrorCodeEnum(Integer code, String msg){
        this.code = code;
        this.msg = msg;
    }
}



参考

https://www.cnblogs.com/jingmoxukong/p/6098351.html


以上是关于Enum的主要内容,如果未能解决你的问题,请参考以下文章

C语言反转单向链表的代码

java中的enum

线程化时访问静态地图时发生故障。

Java 枚举类的基本使用

Ruby 中 [1,2,3].to_enum 和 [1,2,3].enum_for 的区别

使用代码段遍历,枚举类型Enum