枚举

465 阅读6分钟

mp.weixin.qq.com/s/301Yy3vEL…

原理】

写一个枚举,相信大家都会,如:

1public enum City {Guangzhou, Shenzhen, Dongguan}

这是个城市的枚举类,包含广州、深圳、东莞三个城市枚举值,但是它怎么用呢?它的背后的真面目是怎样的呢?

下面我们来反编译一下这个枚举,结果得出:

 1public final class City  extends Enum<City>  { 2    public static final City[] values() { 3        return (City[]) $VALUES.clone(); 4    } 5    public static City valueOf(String name) { 6        return (City) Enum.valueOf(City, name); 7    } 8    // 构造函数 9    private City(String s, int i) {10        super();11    }12    public static final City Guangzhou;13    public static final City Shenzhen;14    public static final City Dongguan;1516    private static final City $VALUES[];17    // 实例化枚举18    static {19        Guangzhou = new City("Guangzhou", 0);20        Shenzhen = new City("Shenzhen", 1);21        Dongguan = new City("Dongguan", 2);22        $VALUES = (new City[] { Guangzhou, Shenzhen, Dongguan });23    }24}

从这个类中我们可以看出几点:

1)是个类 并且是final类,继承与java.lang.Enum类 不可继承。

2)用static块初始化。

3)定义了几个final类型的City对象,并且在static块中初始化。

由此可以知道,enum本质是一个final类,而JavaAPI的设计出的这个Enum,是一个被封装之后的类,旨在提供一种代码简洁而高效的类型管理组件,简化开发者编码。这当然是废话啦,各位看看,同样是功能的两种写法哪一种更简洁?哪一种更值得用?

我们再来看看enum接口类的源码:

1public abstract class Enum<E extends Enum<E>> 2        implements Comparable<E>, Serializable { 3    //枚举常量名称 4    private final String name; 5  //返回枚举常量名称 6    public final String name() { 7        return name; 8    } 9    //枚举常量的序数 初始值为0 根据位置而得出10    private final int ordinal;11//    返回枚举常量的序数12    public final int ordinal() {13        return ordinal;14    }15    //私有构造函数,程序无法直接调用改函数进行初始化16    //它用于由响应枚举类型声明的编译器发出的代码17    //@param name:枚举常量的名称18    //@param ordinal: 枚举常量的序数19    protected Enum(String name, int ordinal) {20        this.name = name;21        this.ordinal = ordinal;22    }23    //和name()是一个意思24    public String toString() {25        return name;26    }27    //判断是否相同对象的函数28    public final boolean equals(Object other) {29        return this==other;30    }31    //为枚举返回一个hashCode32    public final int hashCode() {33        return super.hashCode();34    }35    //克隆函数36    protected final Object clone() throws CloneNotSupportedException {37        throw new CloneNotSupportedException();38    }39    //比较此枚举与指定对象的顺序(编号)。40    //在该对象小于、等于或大于指定对象时,分别返回负整数、零或正整数。41    //枚举常量只能与相同枚举类型的其他枚举常量进行比较。42    //该方法实现的自然顺序就是声明常量的顺序。 43    public final int compareTo(E o) {44        Enum<?> other = (Enum<?>)o;45        Enum<E> self = this;46        if (self.getClass() != other.getClass() && // optimization47            self.getDeclaringClass() != other.getDeclaringClass())48            throw new ClassCastException();49        return self.ordinal - other.ordinal;50    }51// 以下方法略过....52}

有了这个抽象类Enum的源码,我们基本上知道枚举是怎么使用的了,下面是一些常用的方法:

方法名

返回值

说明

name()

String

返回枚举的名称

ordinal()

int

返回枚举常量的序数

compareTo(E o)

int

比较此枚举与指定对象的顺序(编号)。

在该对象小于、等于或大于指定对象时,分别返回负整数、零或正整数。

枚举常量只能与相同枚举类型的其他枚举常量进行比较。

该方法实现的自然顺序就是声明常量的顺序





【使用方式】

Enum类实现三种枚举:

1)最常用:

1public enum Num {2    ONE,TWO,THREE;3}


2)定义带参构造函数:

 1public enum EnumTest{ 2    ONE("1","YI"); 3    private String name; 4    private String  value; 5    //一个参 6    private EnumTest(String name){ 7        this.name=name; 8    } 9    //两个参数10    private EnumTest(String name,String value){11        this.name=name;12        this.value=value;13    }14    //...多个参数15    public static void main(String[] args) {16        System.out.println(EnumTest.ONE.name);17        System.out.println(EnumTest.ONE.value);18    }19}

3)抽象方法实现:

 1public enum EnumTest{ 2    ONE("1") { 3        @Override 4        public void handle() { 5            // TODO Auto-generated method stub 6        } 7    }; 8    private String name; 9    private EnumTest(String name){10        this.name=name;11    }12    //定义抽象方法13    public abstract void handle();14    public static void main(String[] args) {15        //调用16        EnumTest.ONE.handle();17    }18}


【注意事项】

1)不能继承,因为枚举类本身已经继承了Enum抽象类,而Java是单继承

2)枚举的第一行必须是枚举项,所有其它的变量和方法都必须在枚举项后面

3) 枚举类可以定义抽象方法,但没枚举项必须重写所有抽象方法

4)可以在switch中使用枚举,它的使用方法如下:

 1switch(EnumTest.ONE){ 2 3case ONE: 4 5break; 6 7case TWO: 8 9break;1011}


补充:

一、包含抽象方法的枚举类:

定义一个 Calculator 枚举类,有4个枚举值PLUS、MINUS、TIMES、DIVIDE,分别代表加、减、乘、除,该枚举类有一个 calculate() 抽象方法,用于完成计算。


包含抽象方法的枚举类Calculator:

public enum Calculator {    // 加法运算    PLUS { // 花括号部分其实是一个匿名内部子类        @Override        public int calculate(int x, int y) {            return x + y;        }    },    // 减法运算    MINUS { // 花括号部分其实是一个匿名内部子类        @Override        public int calculate(int x, int y) {            // TODO Auto-generated method stub            return x - y;        }    },    // 乘法运算    TIMES { // 花括号部分其实是一个匿名内部子类        @Override        public int calculate(int x, int y) {            return x * y;        }    },    // 除法运算    DIVIDE { // 花括号部分其实是一个匿名内部子类        @Override        public int calculate(int x, int y) {            return x / y;        }    };    //为该枚举类定义一个抽象方法,枚举类中所有的枚举值都必须实现这个方法    public abstract int calculate(int x, int y);}


加、减、乘、除计算:

public class TestDemo {    public static void main(String[] args) {        //加、减、乘、除计算        System.out.println("2 + 2 = " + Calculator.PLUS.calculate(2, 2));        System.out.println("5 - 2 = " + Calculator.MINUS.calculate(5, 2));        System.out.println("2 * 2 = " + Calculator.TIMES.calculate(2, 2));        System.out.println("4 / 2 = " + Calculator.DIVIDE.calculate(4, 2));    }}




二、使用枚举来实mybatis的sqlSessionFactory单例



/**  使用枚举实现SqlSessionFactory单例 @Author Winston @date 2018年10月4日 *  */publicenum SingletonSqlSessionFactoryEnum {   /**    * 定义一个成员变量,如果变量后面有方法要加分号    */   INSTACE;   /**    *SqlSessionFactory对象    */   private  SqlSessionFactory sqlSessionFactory;   /**    * JVM会值调用构造方法一次    * @throws IOException     */   private SingletonSqlSessionFactoryEnum(){      System.out.println("枚举构造方法初始化");      try {         //加载配置文件         Reader read = Resources.getResourceAsReader("config.xml");         sqlSessionFactory = new SqlSessionFactoryBuilder().build(read);      } catch (IOException e) {         e.printStackTrace();      }     }   /**     获取sqlSessionFactory对象实例    @Author Winston    @date 2018年10月4日    @email 940945444@qq.com    @return    @param    */   publicstatic SqlSessionFactory getInstance(){      return SingletonSqlSessionFactoryEnum.INSTACE.sqlSessionFactory;   }}使用publicclass TestSingletonSqlSessionFactoryEnum {   publicstaticvoid main(String[] args) {      //获取对象,构造方法只会初始化一次      System.out.println(SingletonSqlSessionFactoryEnum.getInstance());      System.out.println(SingletonSqlSessionFactoryEnum.getInstance());      System.out.println(SingletonSqlSessionFactoryEnum.getInstance());      System.out.println(SingletonSqlSessionFactoryEnum.getInstance());   }}旁白:枚举类的构造方法JVM只会初始化一次。通常使用枚举来实现单例都是该枚举类只有一个成员属性的时候