java 枚举类定义静态valueOf(java.lang.String)方法的问题及解决

目录
  • 问题的起因
  • 猜测、分析
  • 最终解决方案
  • 枚举类Enum方法简介(valueof,value,ordinal)
    • 我们应该注意到enum类型有如下的一些特征
    • 了解了这些基本特性,我们来看看如何使用它们

问题的起因

起因来自于我对于java枚举类的无知。

我本来想定义这样一个枚举类:

public enum MenuOptions {
    CHAT_ROOM("#1"),
    MENU("#0"),
    ERROR("#9999");

    private String value;

    MenuOptions(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return value;
    }

    // 根据字符串的值返回枚举常量
    public static MenuOptions valueOf(String value) {
        //...
        return MenuOptions.ERROR;
    }
}

关键是定义的这个方法:

我用的IDE是IDEA,jdk版本是1.8,但是编译版本、语言级别是1.7

这里报方法定义已存在,,,???

这个时候,想起来枚举类有一个valueOf方法的,传入的参数是枚举常量的变量名,返回这个枚举常量,然后debug,发现枚举类内部调用了java.lang.Enum类的这个方法:

    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }

猜测、分析

猜测可能是编译的时候,这个类被JDK默认继承了Enum类,通过IDEA查看class反编译文件:

what???什么也没有。。。

使用javap来看这个class文件:

首先,确实可以看到这个类继承自Enum类,然后这个类valueOf(String)调用了Enum.valueOf(Class,String)方法:

but,这个类的valueOf(String)在Enum类里没有找到(下面是Enum类的所有方法声明):

这样看来是JDK编译的时候,动态增加的,不知道猜想是否准确,回头找个时间好好查下资料了解下。

最终解决方案

碰见这样的,我也不知道怎么解决了,本来我这个方法,是想通过传入的值返回相应的枚举值,不是像默认的那样传入枚举量的变量名字符串。

那这样的话,我只能换个名了,,,尴尬。。。如下完整代码 :

public enum MenuOptions {
    CHAT_ROOM("#1"),
    MENU("#0"),
    ERROR("#9999"){
        {
            innerMap.put("#1", "CHAT_ROOM");
            innerMap.put("#0", "MENU");
            innerMap.put("#9999", "ERROR");
        }
    };

    private String value;
    protected Map<String, String> innerMap = new HashMap<>();

    MenuOptions(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return value;
    }

    // 根据字符串的值返回枚举常量
    public static MenuOptions valueOf2(String value) {
        String name = MenuOptions.ERROR.innerMap.get(value.trim().intern());
        if (name == null) {
            return MenuOptions.ERROR;
        }
        MenuOptions option = valueOf(name);

        return option;
    }
}

枚举类Enum方法简介(valueof,value,ordinal)

Enum作为Sun全新引进的一个关键字,看起来很象是特殊的class, 它也可以有自己的变量,可以定义自己的方法,可以实现一个或者多个接口。 当我们在声明一个enum类型时,

我们应该注意到enum类型有如下的一些特征

1.它不能有public的构造函数,这样做可以保证客户代码没有办法新建一个enum的实例。

2.所有枚举值都是public , static , final的。注意这一点只是针对于枚举值,我们可以和在普通类里面定义 变量一样定义其它任何类型的非枚举变量,这些变量可以用任何你想用的修饰符。

3.Enum默认实现了java.lang.Comparable接口。

4.Enum覆载了了toString方法,因此我们如果调用Color.Blue.toString()默认返回字符串”Blue”.

5.Enum提供了一个valueOf方法,这个方法和toString方法是相对应的。调用valueOf(“Blue”)将返回Color.Blue.因此我们在自己重写toString方法的时候就要注意到这一点,一把来说应该相对应地重写valueOf方法。

6.Enum还提供了values方法,这个方法使你能够方便的遍历所有的枚举值。

7.Enum还有一个oridinal的方法,这个方法返回枚举值在枚举类种的顺序,这个顺序根据枚举值声明的顺序而定,这里Color.Red.ordinal()返回0。

了解了这些基本特性,我们来看看如何使用它们

1.遍历所有有枚举值. 知道了有values方法,我们可以轻车熟路地用ForEach循环来遍历了枚举值了。

  for   (Color   c:   Color.values())
  System.out.println(“find   value:”   +   c);   

2.在enum中定义方法和变量,比如我们可以为Color增加一个方法随机返回一个颜色。

public   enum   Color   {
  Red,
  Green,
  Blue;
  /*
  *定义一个变量表示枚举值的数目。
  *(我有点奇怪为什么sun没有给enum直接提供一个size方法).
  */
  private   static   int   number   =   Color.values().length   ;
  /**
  *   随机返回一个枚举值
  @return   a   random   enum   value.
  */
  public   static   Color   getRandomColor(){
  long   random   =   System.currentTimeMillis()   %   number;
  switch   ((int)   random){
   case   0:
    return   Color.Red;
   case   1:
    return   Color.Green;
   case   2:
    return   Color.Blue;
   default   :   return   Color.Red;
  }
  }
  }

可以看出这在枚举类型里定义变量和方法和在普通类里面定义方法和变量没有什么区别。唯一要注意的只是变量和方法定义必须放在所有枚举值定义的后面,否则编译器会给出一个错误。

3.覆载(Override)toString, valueOf方法

前面我们已经知道enum提供了toString,valueOf等方法,很多时候我们都需要覆载默认的toString方法,那么对于enum我们怎么做呢。其实这和覆载一个普通class的toString方法没有什么区别。

….
  public   String   toString(){
  switch   (this){
  case   Red:
   return   "Color.Red ";
  case   Green:
   return   "Color.Green ";
  case   Blue:
   return   "Color.Blue ";
  default:
   return   "Unknow   Color ";
  }
  }
  ….   

这时我们可以看到,此时再用前面的遍历代码打印出来的是

  Color.Red
  Color.Green
  Color.Blue

而不是

  Red
  Green
  Blue.

可以看到toString确实是被覆载了。一般来说在覆载toString的时候我们同时也应该覆载valueOf方法,以保持它们相互的一致性。

4.使用构造函数

虽然enum不可以有public的构造函数,但是我们还是可以定义private的构造函数,在enum内部使用。还是用Color这个例子。

public   enum   Color   {
  Red( "This   is   Red "),
  Green( "This   is   Green "),
  Blue( "This   is   Blue ");
  private   String   desc;
  Color(String   desc){
  this.desc   =   desc;
  }
  public   String   getDesc(){
  return   this.desc;
  }
  }

这里我们为每一个颜色提供了一个说明信息, 然后定义了一个构造函数接受这个说明信息。

要注意这里构造函数不能为public或者protected, 从而保证构造函数只能在内部使用,客户代码不能new一个枚举值的实例出来。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。

5.实现特定的接口

我们已经知道enum可以定义变量和方法,它要实现一个接口也和普通class实现一个接口一样,这里就不作示例了。

6.定义枚举值自己的方法。

前面我们看到可以为enum定义一些方法,其实我们甚至可以为每一个枚举值定义方法。这样,我们前面覆载 toString的例子可以被改写成这样。

  public   enum   Color   {
  Red   {
  public   String   toString(){
   return   "Color.Red ";
  }
  },
  Green   {
  public   String   toString(){
   return   "Color.Green ";
  }
  },
  Blue{
  public   String   toString(){
   return   "Color.Blue ";
  }
  };
  }  

从逻辑上来说这样比原先提供一个“全局“的toString方法要清晰一些。

总的来说,enum作为一个全新定义的类型,是希望能够帮助程序员写出的代码更加简单易懂,个人觉得一般也不需要过多的使用enum的一些高级特性,否则就和简单易懂的初衷想违背了。希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 深入浅出讲解Java中的枚举类

    目录 一.枚举类的使用 二.如何定义枚举类 背景:类的对象只有有限个,确定的.举例如下: > 星期: Monday (星期一).-.. Sunday (星期天) > 性别: Man (男). Woman (女) > 季节: Spring (春节).--.. Winter (冬天) > 支付方式: Cash (现金). WeChatPay (微信). Alipay (支付宝) BankCard (银 行卡). CreditCard (信用卡) > 就职状态: Busy . Fr

  • Day11基础不牢地动山摇-Java基础

    目录 1.Eclipse开发工具 1.1 Eclipse历史 1.2 快捷键 1.3 Debug调试 1.4 JUNIT测试工具 2.Java基础新特性 2.1 可变参数 2.2 foreach输出 2.3 静态导入 3. JDK三大主要特性--泛型 3.1 泛型的引出 3.2 泛型实现 3.3 通配符 3.4 泛型接口 3.5 泛型方法 4.JDK三大主要特性--枚举 4.1 多例与枚举 4.2 Enum类 面试题:请解释enum和Enum的区别? 4.3 枚举中定义其它结构 4.4 枚举应用

  • java枚举enum,根据value值获取key键的操作

    1.ZjlxEnum.java public enum ZjlxEnum implements IEnum { SFZ("1", "居民身份证"), XGZM("2", "香港特区护照/身份证明"), AMZM("3", "澳门特区护照/身份证明"), TWTXZ("4", "台湾居民来往大陆通行证"), JWJZZ("5",

  • Java的枚举,注解和反射(一)

    目录 枚举 什么是枚举? 枚举类的实现 自定义实现枚举类 使用关键字enum定义枚举类 Enum的常用方法 实现接口的枚举类 注解 注解概述 常见的注解 总结 枚举 什么是枚举? 枚举的字面意思就是 一一列举出来 在数学和计算机科学理论中,一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数.这两种类型经常(但不总是)重叠.是一个被命名的整型常数的集合,枚举在日常生活中很常见,例如表示星期的SUNDAY.MONDAY.TUESDAY.WEDNESDAY.THURSDAY

  • 教你如何用好 Java 中的枚举

    目录 1.概览 2.自定义枚举方法 3.使用 == 比较枚举类型 4.在 switch 语句中使用枚举类型 6.EnumSet and EnumMap 6.1. EnumSet 6.2. EnumMap 7. 通过枚举实现一些设计模式 7.1 单例模式 7.2 策略模式 8. Java 8 与枚举 9. Enum 类型的 JSON 表现形式 10. 补充 1.概览 enum关键字在 java5 中引入,表示一种特殊类型的类,其总是继承java.lang.Enum类,更多内容可以自行查看其官方文档

  • java 枚举类中的valueOf用法说明

    目录 枚举类中的valueOf用法 先创建一个BasicEnum的接口 创建一个枚举类实现BasicEnum接口 枚举类valueOf方法的疑问 枚举类中的valueOf用法 前言:今天遇到了一个枚举类的valueOf用法,遇到了一点问题,这里特例写一个demo来测试一下 先创建一个BasicEnum的接口 /** * @Author 徐志 * @date 2020/9/4 12:42 **/ public interface BasicEnum<L,V> { /** * get name *

  • Java SpringBoot在RequestBody中高效的使用枚举参数原理案例详解

    在优雅的使用枚举参数(原理篇)中我们聊过,Spring对于不同的参数形式,会采用不同的处理类处理参数,这种形式,有些类似于策略模式.将针对不同参数形式的处理逻辑,拆分到不同处理类中,减少耦合和各种if-else逻辑.本文就来扒一扒,RequestBody参数中使用枚举参数的原理. 找入口 对 Spring 有一定基础的同学一定知道,请求入口是DispatcherServlet,所有的请求最终都会落到doDispatch方法中的ha.handle(processedRequest, respons

  • java枚举类型-Enum

    目录 前言 应用 定义 基本Enum特性 Enum的静态导入 Enum中添加新方法 Switch语句中的Enum Enum的继承 EnumSet的使用 EnumMap的使用 常量相关方法 枚举值向枚举类型转换 前言 枚举是 Java1.5 引入的新特性,通过关键字 enum 来定义枚举类. 应用 定义 关键字enum可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用. enum WeekEnum { Monday, Tuesday, Wednesday, T

  • Java的枚举,注解和反射(二)

    目录 反射 什么是反射? 反射的用途 反射的具体作用 反射的主要API Class类 总结 反射 什么是反射? 反射是指在程序运行期间,可以通过Reflection Api提供方法可以获取任何类的内部的信息,并能直接操作任意类的方法和属性.反射被视为动态语言的关键. //在反射之前可以做的事情 @Test public void Test1() { //创建Person类的对象 Person person = new Person("name", 78); //通过对象调用其内部的方法

  • java 枚举类定义静态valueOf(java.lang.String)方法的问题及解决

    目录 问题的起因 猜测.分析 最终解决方案 枚举类Enum方法简介(valueof,value,ordinal) 我们应该注意到enum类型有如下的一些特征 了解了这些基本特性,我们来看看如何使用它们 问题的起因 起因来自于我对于java枚举类的无知. 我本来想定义这样一个枚举类: public enum MenuOptions { CHAT_ROOM("#1"), MENU("#0"), ERROR("#9999"); private Stri

  • Java枚举类接口实例原理解析

    这篇文章主要介绍了Java枚举类接口实例原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 枚举类可以实现一个或多个接口.与普通类实现接口完全一样,枚举类实现接口时,需要实现该接口所包含的方法. 如果需要每个枚举值在调用同一个方法时呈现不同的行为,则可以让每个枚举值在{...}匿名块中实现自己的业务逻辑. public interface IGradeHandler { String getGrade(String studentName)

  • Java 枚举类和自定义枚举类和enum声明及实现接口的操作

    1.枚举类 注: JDK1.5之前需要自定义枚举类 JDK 1.5 新增的 enum 关键字用于定义枚举类 若枚举只有一个成员, 则可以作为一种单例模式的实现方式 1.枚举类的属性 1.枚举类对象的属性不应允许被改动, 所以应该使用 private final 修饰 2.枚举类的使用 private final 修饰的属性应该在构造器中为其赋值 3.若枚举类显式的定义了带参数的构造器, 则在列出枚举值时也必须对应的传入参数 2.自定义枚举类 如何自定义枚举类的方法写在注释里 //自定义枚举类 c

  • java枚举类的属性、方法和构造方法应用实战

    本文实例讲述了java枚举类的属性.方法和构造方法应用.分享给大家供大家参考,具体如下: 一 点睛 枚举类也是一种类,只是它是一种比较特殊的类,因此它一样可以使用属性和方法. 枚举类通常应该设计成不可变类,也就说它的属性值不应该允许改变,这样会更安全,而且代码更加简洁.为此,我们应该将枚举类的属性都使用private final修饰. 一旦为枚举类显式定义了带参数的构造器,则列出枚举值时也必须对应地传入参数. 二 简单枚举类实战 1 代码 Gender.java public enum Gend

  • java枚举类的构造函数实例详解

    java枚举类的构造函数实例详解 首先,给出一个例题如下: enum AccountType { SAVING, FIXED, CURRENT; private AccountType() { System.out.println("It is a account type"); } } class EnumOne { public static void main(String[]args) { System.out.println(AccountType.FIXED); } } T

  • 详解Java枚举类在生产环境中的使用方式

    目录 前言 使用 1.确定业务场景状态 2.定义枚举类 3.自定义查询方法 4.测试效果 总结 前言   Java枚举在项目中使用非常普遍,许多人在做项目时,一定会遇到要维护某些业务场景状态的时候,往往会定义一个常量类,然后添加业务场景相关的状态常量.但实际上,生产环境的项目中业务状态的定义大部分是由枚举类来完成的,因为更加清晰明确,还能自定义不同的方法来获取对应的业务状态值,十分方便. 以下代码均为生产环境已上线项目的代码片段,仅供参考. 使用 大体分为确定业务场景状态.定义枚举类.自定义查询

  • Java枚举类使用Lombok方式

    目录 Java枚举类使用Lombok 普通写法 Lombok写法 更精简的写法 Java自定义枚举类 枚举类的创建 枚举类的使用 Java枚举类使用Lombok 枚举类是一个特殊的常量类,由于其特殊的设计,具有简洁性.安全性以及便捷性,在开发中被普遍使用. 本文简单介绍一下如何使用Lombok进行枚举类定义. 按照阿里巴巴的规范,所有的枚举类型字段必须要有注释,说明每个数据项的用途. 这里为了节省篇幅就省略了. 普通写法 public enum BoolEnum {     TRUE(1), F

  • Java枚举类用法实例

    本文实例讲述了Java枚举类用法.分享给大家供大家参考.具体如下: package com.school.stereotype; /** * 活动枚举类型 * @author QiXuan.Chen */ public enum EventStatus { /** * 未发布. */ DRAFT("DRAFT", "未发布"), /** * 已发布. */ PUBLISHED("PUBLISHED", "已发布"); /**

  • idea中Java实体类怎样生成序列化的版本号的方法

    例如: 单击File->单击Settings, 在对话框左侧目录中找到,Editor->Inspections,并单击选中: 在右边的输入框里输入serializable 找到 Serializable class without 'serialVersionUID并在后面打上勾: 于是乎在实体类的类名上面,alt+enter 点击生成序列化版本号 到此这篇关于idea中Java实体类怎样生成序列化的版本号的方法的文章就介绍到这了,更多相关idea实体类序列化内容请搜索我们以前的文章或继续浏览

随机推荐