0
点赞
收藏
分享

微信扫一扫

Java基础-高级特性-枚举介绍

Java工程师知识树 / Java基础


枚举(Enum)

JDK中Enum的API:

概述:

Java在1.5中添加了java.lang.Enum抽象类,它是所有枚举类型基类。JDK1.6后switch语句支持枚举类型。提供了一些基础属性和基础方法。同时,对把枚举用作SetMap也提供了支持,即java.util.EnumSetjava.util.EnumMap

使用枚举的好处:可以将常量按照相同类型组织起来,便于使用与管理

枚举的典型应用场景:错误码、基础类型、基础数据、状态机等。

使用实例

public enum AddressEnum {

    PROVINCE(1, "省份"),
    CITY(2, "城市"),
    COUNTY(3, "区县"),
    TOWN(4, "镇");

    private Integer code;
    private String desc;

    AddressEnum(Integer status, String desc) {
        this.code = status;
        this.desc = desc;
    }

    public Integer getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

    /**
     * 通过编码获取枚举类型
     * @param code
     * @return
     */
    public static AddressEnum getAddressEnumByCode(Integer code) {
        if (code == null) return null;
        for (AddressEnum address : AddressEnum.values()) {
            if (address.getCode().intValue() == code.intValue()) {
                return address;
            }
        }
        return null;
    }

    /**
     * 通过描述获取枚举类型
     * @param desc
     * @return
     */
    public static AddressEnum getAddressEnumByDesc(String desc) {
        if (StrUtil.isBlankIfStr(desc)) return null;
        for (AddressEnum address : AddressEnum.values()) {
            if (StrUtil.equals(address.getDesc(), desc)) {
                return address;
            }
        }
        return null;
    }
}

//编译之后的class文件通过javap反编译之后得到如下代码:
public final class com.hmio.study.enumt.AddressEnum extends java.lang.Enum<com.hmio.study.enumt.AddressEnum> {
    // 枚举产生之前 使用 public static final ... 常量  enum只是做了层封装
  public static final com.hmio.study.enumt.AddressEnum PROVINCE;
  public static final com.hmio.study.enumt.AddressEnum CITY;
  public static final com.hmio.study.enumt.AddressEnum COUNTY;
  public static final com.hmio.study.enumt.AddressEnum TOWN;
  public static com.hmio.study.enumt.AddressEnum[] values();
  public static com.hmio.study.enumt.AddressEnum valueOf(java.lang.String);
  public java.lang.Integer getCode();
  public java.lang.String getDesc();
  public static com.hmio.study.enumt.AddressEnum getAddressEnumByCode(java.lang.Integer);
  public static com.hmio.study.enumt.AddressEnum getAddressEnumByDesc(java.lang.String);
  static {};
}

通过上面实例可以看出:

enum是一种final修饰的类,并且继承了java.lang.Enum类,有自己的方法。

新建Enum类编译之后最终转为的格式为:

public final class XXXEnum extends java.lang.Enum<XXXEnum>

常用方法说明:

方法名称 描述
values() 以数组形式返回枚举类型的所有成员,顺序为声明的顺序。
valueOf(java.lang.String) 将普通字符串转换为枚举实例,是枚举类重新的类方法
compareTo() 比较两个枚举成员在定义时的顺序,因为java.lang.Enum实现了Comparable接口
ordinal() 获取枚举成员的索引位置,java.lang.Enum内方法

枚举与switch

JDK1.6后switch语句支持枚举类型。switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。switch 语句中的变量类型可以是: byte、short、int 、char或者枚举类。从 Java SE 7 开始,switch 支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。

enum Color
{
    RED, GREEN, BLUE;
}
public class MyClass {
  public static void main(String[] args) {
    Color myVar = Color.BLUE;

    switch(myVar) {
      case RED:
        System.out.println("红色");
        break;
      case GREEN:
         System.out.println("绿色");
        break;
      case BLUE:
        System.out.println("蓝色");
        break;
    }
  }
}

枚举与单例模式

单例模式可以说是最常使用的设计模式了,它的作用是确保某个类只有一个实例,自行实例化并向整个系统提供这个实例。在实际应用中,线程池、缓存、日志对象、对话框对象常被设计成单例,总之,选择单例模式就是为了避免不一致状态。

使用枚举实现单例模式

public enum DataSourceEnum {
    DATASOURCE;
    private DBConnection connection = null;
    private DataSourceEnum() {
        connection = new DBConnection();
    }
    public DBConnection getConnection() {
        return connection;
    }
}  

EnumMap 与 EnumSet

为了更好地支持枚举类型,java.util 中添加了两个新类:EnumMap 和 EnumSet。使用它们可以更高效地操作枚举类型。

EnumMap 类

EnumMap 是专门为枚举类型量身定做的 Map 实现。虽然使用其他的 Map(如HashMap)实现也能完成枚举类型实例到值的映射,但是使用 EnumMap 会更加高效。

HashMap 只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以 EnumMap 使用数组来存放与枚举类型对应的值,使得 EnumMap 的效率非常高。

EnumMap 的使用

// 定义数据库类型枚举
public enum DataBaseType {
    MYSQL,ORACLE,DB2,SQLSERVER
}
// 某类中定义的获取数据库URL的方法以及EnumMap的声明
private EnumMap<DataBaseType,String> urls = new EnumMap<DataBaseType,String>(DataBaseType.class);
public DataBaseInfo() {
    urls.put(DataBaseType.DB2,"jdbc:db2://localhost:5000/sample");
    urls.put(DataBaseType.MYSQL,"jdbc:mysql://localhost/mydb");
    urls.put(DataBaseType.ORACLE,"jdbc:oracle:thin:@localhost:1521:sample");
  urls.put(DataBaseType.SQLSERVER,"jdbc:microsoft:sqlserver://sql:1433;Database=mydb");
}
//根据不同的数据库类型,返回对应的URL
// @param type DataBaseType 枚举类新实例
// @return
public String getURL(DataBaseType type) {
    return this.urls.get(type);
}

JDK对EnumMap的描述:

EnumSet 类
public abstract class EnumSet<E extends Enum<E>>
extends AbstractSet<E>
implements Cloneable, Serializable

EnumSet 是枚举类型的高性能 Set 实现,它要求放入它的枚举常量必须属于同一枚举类型。

JDK对EnumSet的描述:

EnumSet使用

public static void main(String[] args) {

    EnumSet<Color> enumSet = EnumSet.noneOf(Color.class);//EnumSet.noneOf()方法创建一个空的set
    System.out.println(enumSet);
    enumSet.add(Color.BLUE);
    enumSet.add(Color.PURPLE);
    System.out.println(enumSet);
    EnumSet<Color> allOfEnumSet = EnumSet.allOf(Color.class);//EnumSet.allOf()方法创建一个满的set
    System.out.println(allOfEnumSet);
    EnumSet<Color> enumSetRange = EnumSet.range(Color.YELLOW,Color.BLUE);//EnumSet.range创建指定范围set
    System.out.println(enumSetRange);
    EnumSet<Color> enumSetComplement = EnumSet.complementOf(enumSetRange);//EnumSet.complementOf补集创建set
    System.out.println(enumSetComplement);
    EnumSet<Color> enumSetRange2 = EnumSet.range(Color.YELLOW,Color.BLUE);
    System.out.println(enumSetRange2);
    EnumSet<Color> enumSet1 = EnumSet.copyOf(enumSetRange2);//EnumSet.copyOf复制创建集合
    System.out.println(enumSet1);
    // EnumSet.copyOf 过滤集合相同的元素
    List<Color> colors = new ArrayList<Color>();
    colors.add(Color.PURPLE);
    colors.add(Color.BLUE);
    colors.add(Color.BLUE);
    System.out.println(colors);
    EnumSet<Color> enumSetCopyOf = EnumSet.copyOf(colors);//EnumSet.copyOf复制创建集合
    System.out.println(enumSet);
}

枚举的好处以及与常量类的区别

  1. 枚举型可以直接与数据库打交道,我通常使用varchar类型存储,对应的是枚举的常量名。(数据库中好像也有枚举类型,不过也没用过)

  2. switch语句支持枚举型,当switch使用int、String类型时,由于值的不稳定性往往会有越界的现象,对于这个的处理往往只能通过if条件筛选以及default模块来处理。而使用枚举型后,在编译期间限定类型,不允许发生越界的情况

  3. 当你使用常量类时,往往得通过equals去判断两者是否相等,使用枚举的话由于常量值地址唯一,可以用==直接对比,性能会有提高

  4. 常量类编译时,是直接把常量的值编译到类的二进制代码里,常量的值在升级中变化后,需要重新编译引用常量的类,因为里面存的是旧值。枚举类编译时,没有把常量值编译到代码里,即使常量的值发生变化,也不会影响引用常量的类。

  5. 枚举类编译后默认为final class,不允许继承可防止被子类修改。常量类可被继承修改、增加字段等,容易导致父类的不兼容。

总结:常量的定义在开发中是必不可少的,虽然无论是通过常量类定义常量还是枚举定义常量都可以满足常量定义的需求。建议使用枚举类型。

举报

相关推荐

0 条评论