java枚举类

什么是枚举

Java中的枚举是一种类型,顾名思义:就是一个一个列举出来。所以它一般都是表示一个有限的集合类型,它是一种类型,在维基百科中给出的定义是:
在这里插入图片描述

使用枚举举例

在Java5之前,其实是没有enum的,所以先来看一下Java5之前对于枚举的使用场景该怎么解决?


public class Month implements Comparable, java.io.Serializable {public static final Month JAN = new Month("January");
public static final Month FEB = new Month("February", 28);
public static final Month MAR = new Month("March");
public static final Month APR = new Month("April", 30);
public static final Month MAY = new Month("May");
public static final Month JUN = new Month("June", 30);
public static final Month JUL = new Month("July");
public static final Month AUG = new Month("August");
public static final Month SEP = new Month("September", 30);
public static final Month OCT = new Month("October");
public static final Month NOV = new Month("November", 30);
public static final Month DEC = new Month("December");private static final Month[] MONTH_ARRAY =
{ JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };private static int count = 0;private final String name;
private final int number;
private final int days;private Month(String name) {
  this(name, 31);
}
private Month(String name, int days) {
  this.name = name;
  this.days = days;
  this.number = ++count;
}
public String getName() {
  return name;
}
public String getAbbev() {
  return name.substring(0, Math.min(3, getName().length()));
}
public int getNumber() {
  return number;
}
public int getDays() {
  return days;
}
public String toString() {
  return name;
}
@Override
public int compareTo(Object o) {
  return getNumber() - ((Month) o).getNumber();
}//readResolve这个方法目的是解决序列化的单例问题
//保证该类对象在序列化后,再进行反序列化时使用在jvm中只有一个对象
Object readResolve() throws java.io.ObjectStreamException {
  return MONTH_ARRAY[number - 1];
}
}

在JDK的枚举类型出现之前,主要依托的是Enumeration这个枚举器接口,具体的设计需要手动去实现,而实现了Enumeration接口的类负责对设计的类似枚举类进行迭代。

JDK1.5以后的用法

在JDK1.5以后,JDK出了enum类型,这个改动大大方便了我们在日常开发中对于枚举的设计与编码。它的写法极其简单,例如最简单的一个月份枚举:

public enum Month{
 JAN, FEB, MAR;//...直到12月份
 //举例方法
 public void method () { 
 }
}

这样我们一个枚举类就写完了,很简洁,很明了。这个就是引入enum的一个好处,我们不需要再关系具体的枚举类的设计,只要enum定义,把需要的枚举值挨个写入即可。

如果我们在定义枚举常量的时候额外传入一些参数,可以这么写:

public enum RGB {
RED(1),GREEN(2), BLUE(3);
private int index;
//构造方法
//但是构造方法的修饰符有限制,不可以是public,只能private
//实际上即使不写private,默认的也是private
private RGB(int index) {
this.index = index;
}
//普通方法
public static int getIndex(RGB rgb) {
return rgb.getIndex();
}
//getter 和 setter方法
...
}

其实从上面这些写法来看,我们在使用的时候没有必要过分在意它是enum 还是class,大多的使用方式都跟普通的Java类没有什么区别,唯独就是在写一些枚举常量的时候,写法有些迥异,但是除此之外,其他方面几乎完全一样:一样可以实现接口,一样需要实现接口中的方法,一样可以重写父类方法(如:toString),甚至一样可以有构造方法。所以仅仅就使用来说,跟传统开发上几乎没有什么区别。

这里唯一需要注意的就是构造函数的修饰符问题,因为enum在JDK中其实就是被设计成了单例模式,所以是不允许外部对其进行实例化的,枚举类型的实例化其实都是JVM帮我们完成,它在加载的时候就会帮我们实例化。

枚举的好处

简化代码
首先一个很明显的感触就是代码量明显减少了,结合前面介绍的在JDK1.5之前的时候,如果需要用到枚举,不同的人会有不同的设计,虽然设计的方式很多种,但是每一种都会有这样或那样的缺陷,而且大多数时候,程序员的编码水平参差不齐,所以如果在没有enum的时候,对于枚举这块的代码设计可能性能上或者说效果上有很大差异。

enum的引入,统一了一个编码规范,无论如何,最起码在枚举的编写上是处于一个水平线的,而且语法极其简单,几乎见名知意,没有什么很难以理解的地方,写出的代码简洁明了,于开发甚至是后期维护上都有很大的好处

线程安全
前面说过枚举类型的实例化不是由程序员自己完成的,而是由虚拟机来做的,在枚举被加载到虚拟机之后就会对其进行实例化,这一步程序员是无感知的,可以看上面它反编译之后的代码,类的内部几乎全部都是static,这也就是说,当真正第一次使用到的时候,虚拟机会对其进行初始化、类加载操作,这个过程是线程安全的,这是Java虚拟机明确规定的,所以说这一步的线程安全有虚拟机来保障是决定可靠的。

序列化安全
前面在介绍enum出现之前的一些设计方案中,第二种就已经考虑到了序列化全的问题,它添加了readResolve方法,为的就是解决在单例模式下,通过序列化后仍然可以绕过常规检查生成多个相同类型的实例情况。关于序列化的分析,可以参考Java序列化。加入了readResolve方法后在反序列化的时候既可以通过该方法自行指定返回一个已经存在与虚拟机内部的对象了,从而避免了因反射调用存在的风险问题。

在使用了enum之后,序列化安全的保障就完全不需要开发人员去关心了,它同样是虚拟机保障的,因为Java的序列化规定,对于enum类型的对象,在序列化的时候只是保存了一个名字,当再次进行反序列化的时候,它会根据这个名字到虚拟机中去找这个enum对象,这期间的writeObject,readObject等等一系列调用全部禁用,所以说枚举是序列化安全的。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值