全面解读Java中的枚举类型enum的使用_java

关于枚举
大多数地方写的枚举都是给一个枚举然后例子就开始switch,可是我想说,我代码里头来源的数据不太可能就是枚举,通常是字符串或数字,比如一个SQL我解析后首先判定SQL类型,通过截取SQL的token,截取出来可能是SELECT、DELETE、UPDATE、INSERT、ALTER等等,但是都是字符串,此时我想用枚举就不行了,我要将字符串转换成枚举怎么转呢,类似的情况还有从数据库取出数据根据一些类型做判定,从页面传入数据,根据不同的类型做不同的操作,但是都是字符串,不是枚举,悲剧的是我很少看到有人写到这个东西;所以我把它写下来,希望有人能用到。

首先为什么要用枚举?我们在什么时候用枚举比较好,用枚举有啥优势?

我认为哈,当你在一些一个范畴类,并可列举,不变化的类型,用以指导程序向不同的地方路由,用枚举是较好的选择;

听起来有点绕,不过有个例子也许可以明白,例如:

我们可以列举下日常工作日所做的事情:

上班、开会、吃饭、睡觉等

我们可以列举医院五官科需要检查人的部位:

眼睛、鼻子、耳朵、嘴巴等

这些都是可以被列举的,且每种事情我们要用不同的方式去做;

当然你可以说:

1、可以用动态方法分派,通过配置文件或annotation;

2、可以使用常量来达到类似的效果;

3、直接通过字符串的equals来表达,用if else来表达

如果用配置加方法分派来做,是灵活,便于修改;但是如果在很多不经常修改的参数上,我们用这中方式往往增加配置的负担,并且当你需要看系统逻辑的时候,需要需要一遍看配置一遍看代码;不过,如果参数是可动态变换的信息,用配置是正确的选择;

而常量的使用,通常在switch case的时候都是数字,字符串在java中是不能做switch case的,使用常量的目的比case 1、case 2 …这种增加了可读性;但是字符串数据也麻烦,除非再映射一次,那没那个必要,其实枚举也差不多是帮你映射了一次,只是它将代码封装了而已吧了,既然他弄好了,而且语法上支持,干嘛不用呢!其次,常量虽然增加了可读性,不过他没有范畴和管理类型的概念,即一个枚举的定义会定义个范畴,可以很好的将这个范围所需要的东西列举出来,而常量通常是些自己定义的一些池,放在一些公共类中或随机定义,都是比较零散的,并且枚举在switch的时候就明确定义好了就在锁列举的范围内case,既可以控制好系统,增加可读性,并且可以随时查看这个范畴的枚举信息到底有那些,达到类似看配置文件的作用;不过还是回到那句话,如果参数是可变的,那么就不适合做枚举,枚举是一定是可列举的,或者说当前系统考虑范围是可以被枚举的,例如上面的医院五官科,可能还有很多没有列举到,但是当前医院只处理几个部位,不处理其他的,就是这个道理;什么是可变的呢,例如URL参数来分派到对应方法,不可能大家加一段逻辑就去加一个枚举,加一个case,此时用【配置+动态方法分派】更好,当然配置可以用文件或annotation而已。

还有最土的就是,通过字符串equals,用if else来实现,呵呵,这个并没有什么不好,只是这个写比较零散,其次,字符串匹配的equals每次匹配都需要对比每个字符,如果你的代码中大量循环,性能并不是很好,其余的看看上面的描述就更加清楚了;

其次,枚举提供一种类型管理的组件,让面向对象的体系更加完善,使得一些类型的管理既可配置化,并可以管理,在使用枚举的地方都可以沿着枚举的定义找到那些有处理过,那些没处理过,而上述几种很难做到;例如,数据库的操作类型定义了10种,那么再判定的过程中就可以讲枚举像配置文件一样看待,而又非常简单的来管理。

最后,枚举绝对是单例的,对比的性能和数字性能相当,既可以得到可读性,也可以得到性能。


enum类型的基本使用
有了这样的理论基础,我们下面就来看Java中的enum枚举类型:
1、可以在enum中添加变量和方法

先来看一段代码示例:

public enum State {
    Normal("正常态", 1), Update("已更新", 2), Deleted("已删除", 3), Fired("已屏蔽", 4);
    // 成员变量
    private String name;
    private int index;

    // 构造方法,注意:构造方法不能为public,因为enum并不可以被实例化
    private State(String name, int index) {
      this.name = name;
      this.index = index;
    }

    // 普通方法
    public static String getName(int index) {
      for (State c : State .values()) {
        if (c.getIndex() == index) {
          return c.name;
        }
      }
      return null;
    }

    // get set 方法
    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public int getIndex() {
      return index;
    }

    public void setIndex(int index) {
      this.index = index;
    }
  }

从上面的代码中我们可以看到,定义完枚举值,然后在其后面加上分号,接着就可以定义其他的变量、方法了。另外需要特别说明的是,enum中的构造方法不可以用public标识,这样做是为了防止用户实例化enum。

2、可以用来定义常量

先来回顾一下Java中如何定义常量吧,看下面一段代码:

public static final int normalState = 1;
private static final int updateState = 2;

下面我们还可以用enum枚举来代替上面的常量定义,代码如下:

public enum State {
 Normal, Update, Deleted, Fired
}

在Java中用enum来定义常量在语法上没有什么优势,但是enum枚举类型可以提供更多的操作功能。

3、在enum中实现接口

先来看下面一段代码:

public interface ICanReadState {
    void read();

    String getState();
}

  public enum State implements ICanReadState {
    Normal("正常态", 1), Update("已更新", 2), Deleted("已删除", 3), Fired("已屏蔽", 4);

    private String name;
    private int index;

    private State(String name, int index) {
      this.name = name;
      this.index = index;
    }

    // 接口方法1

    @Override
    public String getState() {
      return this.name;
    }

    // 接口方法2
    @Override
    public void read() {
      System.out.println(this.index + ":" + this.name);
    }
  }

和一般的类中使用接口一样,enum枚举中同样可以继承接口,并实现接口中的所有方法,这样做的好处在于可以更方便地对枚举中的值进行排序、比较等操作,封装性更好。

实例
我们先定义个简单枚举(这里只是个例子,就简单定义3个变量了):

public enum SqlTypeEnum {
  INSERT ,
  UPDATE ,
  DELETE ,
  SELECT
}

此时解析SQL后,获取出来一个token,我们要获取这个token的枚举怎么获取呢?

这样获取:

String token = "select";
SqlTypeEnum sqlTypeEnum = SqlTypeEnum.valueOf(token.toUpperCase());

如果没获取到,java会抛出一个异常哦:IllegalArgumentException No enum const class SqlTypeEnum.XXX

我做大写处理的原因是因为枚举也是大写的(当然如果你的枚举是小写的,那你就小写,不过混写比较麻烦哈),其实valueOf就是调用了枚举的底层映射:

调用的时候会调用这个方法:

所以内部也是一个HashMap,呵呵!

拿到这个信息后,就可以做想要的操作了:

switch(sqlTypeEnum) {
 case INSERT:处理insert逻辑;break;
 case DELETE:处理delete逻辑;break;
 ....
}

OK,有些时候可能我们不想直接用INSERT、UPDATE这样的字符串在交互中使用,因为很多时候命名规范的要求;

例如定义一些用户操作类型:

1、保存用户信息

2、通过ID获取用户基本信息

3、获取用户列表

4、通过ID删除用户信息

等等

我们可能定义枚举会定义为:

public enum UserOptionEnum {
  SAVE_USER,
  GET_USER_BY_ID,
  GET_USER_LIST,
  DELETE_USER_BY_ID
}

但是系统的方法和一些关键字的配置,通常会写成:

saveUser、getUserById、getUserById、deleteUserById

当然各自有各自的规则,不过中间这层映射,你不想做,就一方面妥协,要么枚举名称全部换掉,貌似挺奇怪的,要么方法名称全部换掉,更加奇怪,要么自己做映射,可以,稍微麻烦点,其实也不麻烦?

我们首先写个将枚举下划线风格的数据转换为驼峰的方法,放在一个StringUtils里面:

public static String convertDbStyleToJavaStyle(String dbStyleString , boolean firstUpper) {
    dbStyleString = dbStyleString.toLowerCase();
    String []tokens = dbStyleString.split("_");
    StringBuilder stringBuilder = new StringBuilder(128);
    int length = 0;
    for(String token : tokens) {
      if(StringUtils.isNotBlank(token)) {
        if(length == 0 && !firstUpper) {
          stringBuilder.append(token);
        }else {
          char c = token.charAt(0);
          if(c >= 'a' || c <= 'z') c = (char)(c - 32);
          stringBuilder.append(c);
          stringBuilder.append(token.substring(1));
        }
      }
      ++length;
    }
    return stringBuilder.toString();
  }

重载一个方法:

public static String convertDbStyleToJavaLocalStyle(String dbStyleString) {
    return convertDbStyleToJavaStyle(dbStyleString , false);
  }

然后定义枚举:

public enum UserOptionEnum {
  SAVE_USER,
  GET_USER_BY_ID,
  GET_USER_LIST,
  DELETE_USER_BY_ID;

  private final static Map<String , UserOptionEnum> ENUM_MAP = new HashMap<String, UserOptionEnum>(64);

  static {
    for(UserOptionEnum v : values()) {
      ENUM_MAP.put(v.toString() , v);
    }
  }

  public staticUserOptionEnum fromString(String v) {
    UserOptionEnum userOptionEnum = ENUM_MAP.get(v);
    return userOptionEnum == null ? DEFAULT :userOptionEnum;
  }

  public String toString() {
    String stringValue = super.toString();
    return StringUtil.convertDbStyleToJavaLocalStyle(stringValue);
  }
}

OK,这样传递一个event参数让如果是:saveUser,此时就用:

String event = "saveUser";//假如这里得到参数
UserOptionEnum enum = UserOptionEnum.fromString(event);

其实就是自己做了一个hashMap,我这加了一个fromString,因为枚举有一些限制,有些方法不让你覆盖,比如valueOf方法就是这样。

其实没啥好讲的了,非要说,再说说枚举加一些自定义变量吧,其实枚举除了是单例的外,其余的和普通类也相似,它也可以有构造方法,只是默认情况下不是而已,也可以提供自定义的变量,然后获取set、get方法,但是如果有set的话,线程不是安全的哦,要注意这点;所以一般是构造方法就写好了:

public enum SqlTypeEnum {
  INSERT("insert into"),
  DELETE("delete from")
  ......省略;

  private String name;//定义自定义的变量

  private SqlTypeEnum(String name) {
   this.name = name;
  }

  public String getName() {
    return name;
  }

  public String toString() {
    return name + " 我靠";//重写toString方法
 }
 //一般不推荐
 public void setName(String name) {
    this.name = name;
 }
}

调用下:

SqlTypeEnum sqlTypeEnum = SqlTypeEnum.valueOf("INSERT");
System.out.println(sqlTypeEnum);
System.out.println(sqlTypeEnum.getName());

不推荐也调用下:

sqlTypeEnum.setName("我靠");

在另一个线程:

SqlTypeEnum sqlTypeEnum = SqlTypeEnum.valueOf("INSERT");
System.out.println(sqlTypeEnum);
System.out.println(sqlTypeEnum.getName());

发现结果被改了,呵呵!

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, enum
枚举
枚举类型enum用法、java枚举类型enum用法、c 枚举类型enum用法、ios枚举类型enum用法、php枚举类型enum用法,以便于您获取更多的相关知识。

时间: 2024-10-30 21:09:35

全面解读Java中的枚举类型enum的使用_java的相关文章

java中的枚举类型详细介绍_java

枚举中有values方法用于按照枚举定义的顺序生成一个数组,可以用来历遍.我们自定义的枚举类都是继承自java.lang.Enum,拥有一下实例中的功能: 复制代码 代码如下: //: enumerated/EnumClass.java // Capabilities of the Enum class import static net.mindview.util.Print.*; enum Shrubbery { GROUND, CRAWLING, HANGING } public clas

C/C++中枚举类型(enum)

如果一个变量你需要几种可能存在的值,那么就可以被定义成为枚举类型.之所以叫枚举就是说将变量或者叫对象可能存在的情况也可以说是可能的值一一例举出来. 举个例子来说明一吧,为了让大家更明白一点,比如一个铅笔盒中有一支笔,但在没有打开之前你并不知道它是什么笔,可能是铅笔也可能是钢笔,这里有两种可能,那么你就可以定义一个枚举类型来表示它! enum box{pencil,pen};//这里你就定义了一个枚举类型的变量叫box,这个枚举变量内含有两个元素也称枚举元素在这里是pencil和pen,分别表示铅

java中的枚举enum,如何实现

问题描述 java中的枚举enum,如何实现 这两天在想java中的枚举,不是很明白,java中的枚举除自身的枚举成员外,还可以实现接口,可以有构造函数及可以定义方法. c#中的枚举简简单单的值类型,而java中的枚举是引用类型. 在c#项目中,经常用枚举, public enum FileType { Unknow=0 Word=1 Excel=2 } public T NumToEnum(int number) { try { if (Enum.IsDefined(typeof(T) num

java中的枚举问题中的变量

问题描述 java中的枚举问题中的变量 新人初学java,在学到枚举的时候遇到了问题,求教各位 枚举中有这样一段定义 public class WeekDay(){ private WeekDay(){} public final static WeekDay SUN = new WeekDay() ...... } 后面就是这样得一些定义星期的代码 不明白的地方: 1.这里是枚举的问题:为什么创建对象可以在这个类的内部,一般来说,不是一般只有在另一个类里创建这个类的对象算是正确吗? 2. 这里

高阶Java-Java枚举类型enum应用详解

java的Enum枚举类型终于在j2se1.5出现了.之前觉得它只不过是鸡肋而已,可有可无.毕竟这么多年来,没有它,大家不都过得很好吗?今日看<Thinking in Java>4th edition,里面有一句话"有时恰恰因为它,你才能够"优雅而干净"地解决问题.优雅与清晰很重要,正式它们区别了成功的解决方案与失败的解决方案.而失败的解决方案就是因为其他人无法理他."使用Enum枚举类型,可以将以前笨拙的代码变得优雅简单?但是,我同时也在思考另外一个问

自定义控件中使用枚举类型的属性

  在控件中定义枚举类型的属性 public  enum DTableStateSelect    {          ShowAddnew = 1,     SaveAddnew = 2,     ShowEdit     = 3,     SaveEdit     = 4,     Delete     = 5,     Show         = 6,     List         = 0     }    private DTableStateSelect _DTableStat

java中的数组类型的数据能存储到栈空间吗

问题描述 java中的数组类型的数据能存储到栈空间吗 我们知道堆空间存储大数据,栈空间的数据先进后出, java中的数组类型的数据能存储到栈空间吗 解决方案 基本类型产生了一个值存放在栈中,变量的值就是栈的地址处的值. 引用类型则产生了一个对象,存放在内存堆中,同时将内存堆对象的指针地址(引用地址)存放在了栈中,变量的值实际是栈中的引用地址. 解决方案二: java中所有对象和数组都是在堆上分配内存的,,栈内存用来存放局部变量 解决方案三: java 存储不同类型数据Java实现登录.注册(使用

Java中,double类型的两个小数相减,值不正确

问题描述 Java中,double类型的两个小数相减,值不正确 double num1 = 0.03; double num2 = 0.02; double num; num = num1 - num2; 此时得到的num!= 0.01,而是等于0.0099....998:请问这是为什么啊?这是由于double类型的精度造成的嘛?谢谢. 解决方案 浮点数存储肯定有精度误差,特别是小数点后面,可以用BigDecemal这个类做

java数组-java中的char类型数组怎么对其赋值?

问题描述 java中的char类型数组怎么对其赋值? 刚学期望得到大家回答,在网上没有搜索到,网上都是写string的用scanner.next().谢谢了 解决方案 String str="hahah"://创建字符串 char[] chArray=new char[10];//创建一个char空数组 chArray=str.toCharArray();//将字符串赋值进去 解决方案二: Scanner方法中没有直接读取character的方法,用String转换好了. 解决方案三: