关于Java 中Enum 的全方位剖析

来源:互联网 发布:java的前景怎么样 编辑:程序博客网 时间:2024/06/09 21:25

如果你受够了如下这种写法,那么这篇文章正好适合你:

setWeek(1);// ...private static final int MONDAY = 1;private static final int TUESDAY = 2;// ... setWeek(MONDAY);

这种方法有如下几个缺点:

  • 不会进行安全检查,也就是说当传递的参数是100,它也不会报出编译错误;
  • 可读性较差,类似setWeek(1)这种magic number,真是让人抓狂;

1. Enum的基本原理

针对这个问题Java提供了解决办法,通过Enum类型来完成,初次看到这个类型可能会有一点疑惑究竟是什么东西,和普通的类有什么不同,为了解决这个疑惑,我们首先弄清楚其中的原理,如下很简单常见枚举类型:

public enum Person{  MALE, FEMALE}

在编译之后使用JDK自带的javap工具进行反编译查看字节码文件,如下:

这里写图片描述

从字节码文件中看可以得到一下信息:

  • Enum类型Person实际上是继承自java.lang.Enum<Person>的类,所以不能再继承别的类,但是可以实现接口;
  • 由于类被final修饰,所以不能再被别的类继承;
  • 每个枚举常量都是该类的一个实例,并且被public static final修饰;
  • 该类有两个隐式静态的方法values()valueOf();
  • 还有一个静态代码段static{}

从上可以看出Enum其实就是通过公有静态的字段来达到和private static final int MONDAY = 1相同的效果。

更进一步去查看反编译生成的字节码java -p Person.class,如下:

这里写图片描述

从上面的字节码可以看出其实Enum的实现并不复杂,只是被JDK封装的很复杂。

2. 基本使用方法

2.1 两个有用的方法

由于Enum枚举类型是继承自java.lang.Enum<Person>的类,所以java.lang.Enum<Person>其中的方法也可以被使用:

  • name():返回枚举常量的名称;
  • ordinal():返回枚举常量在枚举声明中的位置序号,第一个常量的位置是0;

但是这里有一个问题需要说一下,不要通过枚举的序号来唯一标识一个枚举常量,因为如果顺序改变,同一个枚举常量的序号就会变化,而最好采用一个字段来和枚举常量建立联系,如下这种写法是推荐的:

public enum Person{    MALE("M"), FEMALE("F");    private String value;    Person(String value){        this.value = value;    }    public String getValue(){        return this.value;    }}

注意Enum中的构造函数不能使用public修饰,这也暗示我们枚举类型不推荐在外部实例化

另外对于name()方法,JDK也不建议我们直接使用,而是通过toString()方法返回可读性性更强的name。

2.2 用于switch

一般来说在使用switch的时候第一反应是使用int类型进行判断,但是Enum出现之后也得到了switch支持,具体使用方法如下:

public class Main{    public static void main(String[] args) {        Person person = Person.MALE;        switch (person){            case MALE:                System.out.println("male");                break;            case FEMALE:                System.out.println("male");                break;            default:                break;        }    }    public enum Person{        MALE("M"), FEMALE("F");        private String value;        Person(String value){            this.value = value;        }        public String getValue(){            return this.value;        }    }}

那它到底是怎么执行的呢?还是使用javap -c Main看一下,如下:

这里写图片描述

从上我们发现,具体在底层实现的时候还是使用int进行判断,只不过Enum类型使用ordinal()函数进行的转换。

2.3 隐式方法values()

通过使用values()方法遍历其中的枚举常量,如下:

public static Person getPerson(String value){    return Arrays.asList(Person.values()).stream()        .filter(person -> value.equalsIgnoreCase(person.getValue()))        .findAny().get();}

2.4 EnumSet && EnumMap

伴随着Enum的出现也相应的出现了两个集合类EnumSetEnumMap,由于这两个类从没使用过,所以就不展开说了,可以看如下的相关文章。

相关文章:


  • Java 语言中 Enum 类型的使用介绍
0 0
原创粉丝点击