广告
返回顶部
首页 > 资讯 > 精选 >Java枚举类知识详细讲解
  • 660
分享到

Java枚举类知识详细讲解

2023-06-02 15:06:29 660人浏览 八月长安
摘要

本篇内容主要讲解“Java枚举类知识详细讲解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java枚举类知识详细讲解”吧!枚举(enum)类型是Java 5新增的特性,它是一种新的类型,允许用常

本篇内容主要讲解“Java枚举类知识详细讲解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java枚举类知识详细讲解”吧!

枚举(enum)类型是Java 5新增的特性,它是一种新的类型,允许用常量来表示特定的数据片断,而且全部都以类型安全的形式来表示。

初探枚举类

在程序设计中,有时会用到由若干个有限数据元素组成的集合,如一周内的星期一到星期日七个数据元素组成的集合,由三种颜色红、黄、绿组成的集合,一个工作班组内十个职工组成的集合等等,程序中某个变量取值仅限于集合中的元素。此时,可将这些数据集合定义为枚举类型。

因此,枚举类型是某类数据可能取值的集合,如一周内星期可能取值的集合为:
  { Sun,Mon,Tue,Wed,Thu,Fri,Sat}
  该集合可定义为描述星期的枚举类型,该枚举类型共有七个元素,因而用枚举类型定义的枚举变量只能取集合中的某一元素值。由于枚举类型是导出数据类型,因此,必须先定义枚举类型,然后再用枚举类型定义枚举型变量。 

enum <枚举类型名>   { <枚举元素表> };    其中:关键词enum表示定义的是枚举类型,枚举类型名由标识符组成,而枚举元素表由枚举元素或枚举常量组成。例如:   enum weekdays   { Sun,Mon,Tue,Wed,Thu,Fri,Sat };  定义了一个名为 weekdays的枚举类型,它包含七个元素:Sun、Mon、Tue、Wed、Thu、Fri、Sat。

在编译器编译程序时,给枚举类型中的每一个元素指定一个整型常量值(也称为序号值)。若枚举类型定义中没有指定元素的整型常量值,则整型常量值从0开始依次递增,因此,weekdays枚举类型的七个元素Sun、Mon、Tue、Wed、Thu、Fri、Sat对应的整型常量值分别为0、1、2、3、4、5、6。
  注意:在定义枚举类型时,也可指定元素对应的整型常量值。

例如,描述逻辑值集合{TRUE、FALSE}的枚举类型boolean可定义如下:enum boolean   { TRUE=1 ,FALSE=0 };该定义规定:TRUE的值为1,而FALSE的值为0。  而描述颜色集合{red,blue,green,black,white,yellow}的枚举类型colors可定义如下:enum colors   {red=5,blue=1,green,black,white,yellow};  该定义规定red为5 ,blue为1,其后元素值从2 开始递增加1。green、black、white、yellow的值依次为2、3、4、5。

  此时,整数5将用于表示二种颜色red与yellow。通常两个不同元素取相同的整数值是没有意义的。枚举类型的定义只是定义了一个新的数据类型,只有用枚举类型定义枚举变量才能使用这种数据类型。

枚举类-语法

enum 与 class、interface 具有相同地位;
可以继承多个接口;
可以拥有构造器、成员方法、成员变量;
1.2 枚举类与普通类不同之处

默认继承 java.lang.Enum 类,所以不能继承其他父类;其中 java.lang.Enum 类实现了 java.lang.Serializable 和 java.lang.Comparable 接口;

使用 enum 定义,默认使用 final 修饰,因此不能派生子类;

构造器默认使用 private 修饰,且只能使用 private 修饰;

枚举类所有实例必须在第一行给出,默认添加 public static final 修饰,否则无法产生实例;

枚举类的具体使用

这部分内容参考https://blog.csdn.net/qq_27093465/article/details/52180865

常量
public class 常量 {}enum Color {    Red, Green, Blue, Yellow}
switch

jdk1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。

public static void showColor(Color color) {        switch (color) {            case Red:                System.out.println(color);                break;            case Blue:                System.out.println(color);                break;            case Yellow:                System.out.println(color);                break;            case Green:                System.out.println(color);                break;        }    }
向枚举中添加新方法

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。

enum Color {    //每个颜色都是枚举类的一个实例,并且构造方法要和枚举类的格式相符合。    //如果实例后面有其他内容,实例序列结束时要加分号。    Red("红色", 1), Green("绿色", 2), Blue("蓝色", 3), Yellow("黄色", 4);    String name;    int index;    Color(String name, int index) {        this.name = name;        this.index = index;    }    public void showAllColors() {        //values是Color实例的数组,在通过index和name可以获取对应的值。        for (Color color : Color.values()) {            System.out.println(color.index + ":" + color.name);        }    }}
覆盖枚举的方法

所有枚举类都继承自Enum类,所以可以重写该类的方法
下面给出一个toString()方法覆盖的例子。

@Overridepublic String toString() {    return this.index + ":" + this.name;}
实现接口

所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。

enum Color implements Print{    @Override    public void print() {        System.out.println(this.name);    }}
使用接口组织枚举

搞个实现接口,来组织枚举,简单讲,就是分类吧。如果大量使用枚举的话,这么干,在写代码的时候,就很方便调用啦。

public class 用接口组织枚举 {    public static void main(String[] args) {        Food cf = chineseFood.dumpling;        Food jf = Food.JapaneseFood.fishpiece;        for (Food food : chineseFood.values()) {            System.out.println(food);        }        for (Food food : Food.JapaneseFood.values()) {            System.out.println(food);        }    }}interface Food {    enum JapaneseFood implements Food {        suse, fishpiece    }}enum chineseFood implements Food {    dumpling, tofu}
枚举类集合

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。

EnumSet在JDK中没有找到实现类,这里写一个EnumMap的例子

public class 枚举类集合 {    public static void main(String[] args) {        EnumMap<Color, String> map = new EnumMap<Color, String>(Color.class);        map.put(Color.Blue, "Blue");        map.put(Color.Yellow, "Yellow");        map.put(Color.Red, "Red");        System.out.println(map.get(Color.Red));    }}

使用枚举类的注意事项

Java枚举类知识详细讲解

枚举类型对象之间的值比较,是可以使用==,直接来比较值,是否相等的,不是必须使用equals方法的哟。

因为枚举类Enum已经重写了equals方法

public final boolean equals(Object other) {    return this==other;}

枚举类的实现原理

这部分参考Https://blog.csdn.net/mhmyqn/article/details/48087247

Java从JDK1.5开始支持枚举,也就是说,Java一开始是不支持枚举的,就像泛型一样,都是JDK1.5才加入的新特性。通常一个特性如果在一开始没有提供,在语言发展后期才添加,会遇到一个问题,就是向后兼容性的问题。

像Java在1.5中引入的很多特性,为了向后兼容,编译器会帮我们写的源代码做很多事情,比如泛型为什么会擦除类型,为什么会生成桥接方法,foreach迭代,自动装箱/拆箱等,这有个术语叫“语法糖”,而编译器的特殊处理叫“解语法糖”。那么像枚举也是在JDK1.5中才引入的,又是怎么实现的呢?

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

接下来定义一个简单的枚举类

public enum Day {    MONDAY {        @Override        void say() {            System.out.println("MONDAY");        }    }    , TUESDAY {        @Override        void say() {            System.out.println("TUESDAY");        }    }, FRIDAY("work"){        @Override        void say() {            System.out.println("FRIDAY");        }    }, SUNDAY("free"){        @Override        void say() {            System.out.println("SUNDAY");        }    };    String work;    //没有构造参数时,每个实例可以看做常量。    //使用构造参数时,每个实例都会变得不一样,可以看做不同的类型,所以编译后会生成实例个数对应的class。    private Day(String work) {        this.work = work;    }    private Day() {    }    //枚举实例必须实现枚举类中的抽象方法    abstract void say ();}

反编译结果

D:\MyTech\out\production\MyTech\com\javase\枚举类>javap Day.classCompiled from "Day.java"public abstract class com.javase.枚举类.Day extends java.lang.Enum<com.javase.枚举类.Day> {  public static final com.javase.枚举类.Day MONDAY;  public static final com.javase.枚举类.Day TUESDAY;  public static final com.javase.枚举类.Day FRIDAY;  public static final com.javase.枚举类.Day SUNDAY;  java.lang.String work;  public static com.javase.枚举类.Day[] values();  public static com.javase.枚举类.Day valueOf(java.lang.String);  abstract void say();  com.javase.枚举类.Day(java.lang.String, int, com.javase.枚举类.Day$1);  com.javase.枚举类.Day(java.lang.String, int, java.lang.String, com.javase.枚举类.Day$1);  static {};}

可以看到,一个枚举在经过编译器编译过后,变成了一个抽象类,它继承了java.lang.Enum;而枚举中定义的枚举常量,变成了相应的public static final属性,而且其类型就抽象类的类型,名字就是枚举常量的名字.

同时我们可以在Operator.class的相同路径下看到四个内部类的.class文件com/mikan/Day$1.class、com/mikan/Day$2.class、com/mikan/Day$3.class、com/mikan/Day$4.class,也就是说这四个命名字段分别使用了内部类来实现的;同时添加了两个方法values()和valueOf(String);我们定义的构造方法本来只有一个参数,但却变成了三个参数;同时还生成了一个静态代码块。这些具体的内容接下来仔细看看。

下面分析一下字节码中的各部分,其中:

InnerClasses:     static #23; //class com/javase/枚举类/Day$4     static #18; //class com/javase/枚举类/Day$3     static #14; //class com/javase/枚举类/Day$2     static #10; //class com/javase/枚举类/Day$1

从中可以看到它有4个内部类,这四个内部类的详细信息后面会分析。

static {};    descriptor: ()V    flags: ACC_STATIC    Code:      stack=5, locals=0, args_size=0         0: new           #10                 // class com/javase/枚举类/Day$1         3: dup         4: ldc           #11                 // String MONDAY         6: iconst_0         7: invokespecial #12                 // Method com/javase/枚举类/Day$1."<init>":(Ljava/lang/String;I)V        10: putstatic     #13                 // Field MONDAY:Lcom/javase/枚举类/Day;        13: new           #14                 // class com/javase/枚举类/Day$2        16: dup        17: ldc           #15                 // String TUESDAY        19: iconst_1        20: invokespecial #16                 // Method com/javase/枚举类/Day$2."<init>":(Ljava/lang/String;I)V        //后面类似,这里省略}

其实编译器生成的这个静态代码块做了如下工作:分别设置生成的四个公共静态常量字段的值,同时编译器还生成了一个静态字段$VALUES,保存的是枚举类型定义的所有枚举常量
编译器添加的values方法:

public static com.javase.Day[] values();    flags: ACC_PUBLIC, ACC_STATIC    Code:      stack=1, locals=0, args_size=0         0: getstatic     #2                  // Field $VALUES:[Lcom/javase/Day;         3: invokevirtual #3                  // Method "[Lcom/mikan/Day;".clone:()Ljava/lang/Object;         6: checkcast     #4                  // class "[Lcom/javase/Day;"         9: areturn  这个方法是一个公共的静态方法,所以我们可以直接调用该方法(Day.values()),返回这个枚举值的数组,另外,这个方法的实现是,克隆在静态代码块中初始化的$VALUES字段的值,并把类型强转成Day[]类型返回。

造方法为什么增加了两个参数?

有一个问题,构造方法我们明明只定义了一个参数,为什么生成的构造方法是三个参数呢?

从Enum类中我们可以看到,为每个枚举都定义了两个属性,name和ordinal,name表示我们定义的枚举常量的名称,如FRIDAY、TUESDAY,而ordinal是一个顺序号,根据定义的顺序分别赋予一个整形值,从0开始。在枚举常量初始化时,会自动为初始化这两个字段,设置相应的值,所以才在构造方法中添加了两个参数。即:另外三个枚举常量生成的内部类基本上差不多,这里就不重复说明了。

我们可以从Enum类的代码中看到,定义的name和ordinal属性都是final的,而且大部分方法也都是final的,特别是clone、readObject、writeObject这三个方法,这三个方法和枚举通过静态代码块来进行初始化一起。

它保证了枚举类型的不可变性,不能通过克隆,不能通过序列化和反序列化来复制枚举,这能保证一个枚举常量只是一个实例,即是单例的,所以在effective java中推荐使用枚举来实现单例。

枚举类实战

实战一无参

(1)定义一个无参枚举类

enum SeasonType {    spring, SUMMER, AUTUMN, WINTER}

(2)实战中的使用

// 根据实际情况选择下面的用法即可SeasonType springType = SeasonType.SPRING;    // 输出 SPRING String springString = SeasonType.SPRING.toString();    // 输出 SPRING

实战二有一参

(1)定义只有一个参数的枚举类

enum SeasonType {    // 通过构造函数传递参数并创建实例    SPRING("spring"),    SUMMER("summer"),    AUTUMN("autumn"),    WINTER("winter");    // 定义实例对应的参数    private String msg;    // 必写:通过此构造器给枚举值创建实例    SeasonType(String msg) {        this.msg = msg;    }    // 通过此方法可以获取到对应实例的参数值    public String getMsg() {        return msg;    }}

(2)实战中的使用

// 当我们为某个实例类赋值的时候可使用如下方式String msg = SeasonType.SPRING.getMsg();    // 输出 spring

实战三有两参

(1)定义有两个参数的枚举类

public enum Season {    // 通过构造函数传递参数并创建实例    SPRING(1, "spring"),    SUMMER(2, "summer"),    AUTUMN(3, "autumn"),    WINTER(4, "winter");    // 定义实例对应的参数    private Integer key;    private String msg;    // 必写:通过此构造器给枚举值创建实例    Season(Integer key, String msg) {        this.key = key;        this.msg = msg;    }    // 很多情况,我们可能从前端拿到的值是枚举类的 key ,然后就可以通过以下静态方法获取到对应枚举值    public static Season valueofKey(Integer key) {        for (Season season : Season.values()) {            if (season.key.equals(key)) {                return season;            }        }        throw new IllegalArgumentException("No element matches " + key);    }    // 通过此方法可以获取到对应实例的 key 值    public Integer geTKEy() {        return key;    }    // 通过此方法可以获取到对应实例的 msg 值    public String getMsg() {        return msg;    }}

(2)实战中的使用

// 输出 key 为 1 的枚举值实例Season season = Season.valueofKey(1);// 输出 SPRING 实例对应的 keyInteger key = Season.SPRING.getKey();// 输出 SPRING 实例对应的 msgString msg = Season.SPRING.getMsg();

枚举类总结

其实枚举类懂了其概念后,枚举就变得相当简单了,随手就可以写一个枚举类出来。所以如上几个实战小例子一定要先搞清楚概念,然后在练习几遍就 ok 了。

重要的概念,我在这里在赘述一遍,帮助老铁们快速掌握这块知识,首先记住,枚举类中的枚举值可以没有参数,也可以有多个参数,每一个枚举值都是一个实例;

并且还有一点很重要,就是如果枚举值有 n 个参数,那么构造函数中的参数值肯定有 n 个,因为声明的每一个枚举值都会调用构造函数去创建实例,所以参数一定是一一对应的;既然明白了这一点,那么我们只需要在枚举类中把这 n 个参数定义为 n 个成员变量,然后提供对应的 get() 方法,之后通过实例就可以随意的获取实例中的任意参数值了。

如果想让枚举类更加的好用,就可以模仿我在实战三中的写法那样,通过某一个参数值,比如 key 参数值,就能获取到其对应的枚举值,然后想要什么值,就 get 什么值就好了。

枚举 api

我们使用 enum 定义的枚举类都是继承 java.lang.Enum 类的,那么就会继承其 API ,常用的 API 如下:

  • String name()

获取枚举名称

  • int ordinal()

获取枚举的位置(下标,初始值为 0 )

  • valueof(String msg)

通过 msg 获取其对应的枚举类型。(比如实战二中的枚举类或其它枚举类都行,只要使用得当都可以使用此方法)

  • values()

获取枚举类中的所有枚举值(比如在实战三中就使用到了)

总结

枚举本质上是通过普通的类来实现的,只是编译器为我们进行了处理。每个枚举类型都继承自java.lang.Enum,并自动添加了values和valueOf方法。

而每个枚举常量是一个静态常量字段,使用内部类实现,该内部类继承了枚举类。所有枚举常量都通过静态代码块来进行初始化,即在类加载期间就初始化

另外通过把clone、readObject、writeObject这三个方法定义为final的,同时实现是抛出相应的异常。这样保证了每个枚举类型及枚举常量都是不可变的。可以利用枚举的这两个特性来实现线程安全的单例。

到此,相信大家对“Java枚举类知识详细讲解”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

--结束END--

本文标题: Java枚举类知识详细讲解

本文链接: https://www.lsjlt.com/news/230497.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java枚举类知识详细讲解
    本篇内容主要讲解“Java枚举类知识详细讲解”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java枚举类知识详细讲解”吧!枚举(enum)类型是Java 5新增的特性,它是一种新的类型,允许用常...
    99+
    2023-06-02
  • Java 枚举详细讲解
    目录 什么是枚举? 如何使用Java枚举? 如何使用Java枚举中的常量值? 如何在Java枚举中添加方法? 什么是枚举? 枚举是一种特殊的数据类型,用于定义具有固定个数的常量集。它可以帮助我们更好地管理常量,使代码更易于阅读和维护。 ...
    99+
    2023-09-01
    java 开发语言 javase 面向对象 枚举
  • Golang表示枚举类型的详细讲解
    枚举,是一种重要的数据类型,由一组键值对组成,通常用来在编程语言中充当常量的标识符。在主流行编程语言如 c、 java 等,都有原生支持。在 go 中,大家却找不到 enum 或者...
    99+
    2022-11-12
  • 深入浅出讲解Java中的枚举类
    目录一、枚举类的使用 二、如何定义枚举类 背景:类的对象只有有限个,确定的。举例如下: > 星期: Monday (星期一)、….、 Sunday (星期天) > 性别:...
    99+
    2022-11-12
  • PHP基础知识详细讲解
    目录一、简介二、php基本语法三、变量和作用域四、常量五、数据类型六、运算符七、流程控制八、超全局变量一、简介 基础知识: 需要一定的html和css的语法知识 基本概念: PHP(...
    99+
    2022-12-03
    PHP基础知识 PHP基础语法
  • Java基础之枚举Enum类案例详解
    目录一、文章序言二、代码实践三、面试相关一、文章序言 Java中引用类型:数组、类、接口、枚举、注解 枚举这个既熟悉又陌生的东西具体再哪里可以使用呢? 什么是枚举? 枚举是一个引用...
    99+
    2022-11-12
  • Java中枚举类的用法示例详解
    目录1.引入枚举类2.实现枚举类3.枚举类的使用注意事项4.枚举的常用方法5.enum细节1.引入枚举类 Java 枚举是一个特殊的类,一般表示一组常量,比如一年的 4 个季节,一个...
    99+
    2022-11-13
  • 四个实例超详细讲解Java 贪心和枚举的特点与使用
    目录贪心:枚举:1.朴素枚举2.状压枚举   算法题1:示例算法题2:示例算法题3: 示例1示例2算法题4: 示例笔试技巧:学会根据数据范围猜...
    99+
    2022-11-13
  • java枚举类的构造函数实例详解
    java枚举类的构造函数实例详解首先,给出一个例题如下:enum AccountType{ SAVING, FIXED, CURRENT; private AccountType() { System.out.println(“...
    99+
    2023-05-31
    java 枚举类 构造函数
  • Java中枚举类enum的values()方法的详解
    Java中枚举类enum的values()方法的详解 简介: 枚举中的一个特殊方法,values(), 在Enum 的 API 文档中也找不到这个方法,当点击values()时,也会跳到本类上。 此方法可以理解为:将枚举类转变为一个枚举类型...
    99+
    2023-08-18
    java 开发语言 jvm
  • Java 抽象类详细讲解
    目录 Java抽象类概念 Java抽象类示例 继承Animal类的子类的示例 Java抽象类详细使用方法 1、定义抽象类 2、继承抽象类 3、实现抽象方法 4、完整示例代码 Java抽象类概念 Java中抽象类是指用abstract关键...
    99+
    2023-09-04
    java jvm 开发语言 javase 面向对象
  • 超详细的PHP入门知识点讲解
    目录 一、简介 二、php基本语法  二、变量和作用域 三、常量 四、数据类型 五、运算符 六、流程控制 七、超全局变量 一、简介 基础知识: 需要一定的html和css的语法知识 基本概念: PHP(超文本预处理器)是一种通用开源脚本...
    99+
    2023-09-25
    php 开发语言
  • 前端组件化基础知识详细讲解
    目录组件的基本概念对象与组件的区别组件 Component特性 AttributeAttribute 对比 PropertyAttribute:Property:Class 属性St...
    99+
    2022-11-12
  • Java中ThreadPoolExecutor类的详细讲解
    这篇文章主要介绍“Java中ThreadPoolExecutor类的详细讲解”,在日常操作中,相信很多人在Java中ThreadPoolExecutor类的详细讲解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答...
    99+
    2023-06-20
  • Java泛型枚举Annotation接口详细解读与Eclipse发展
    目录1、Eclipse开发工具1.1 Eclipse历史1.2 快捷键1.3 Debug调试1.4 JUNIT测试工具2、Java基础新特性2.1 可变参数2.2 foreach输出...
    99+
    2022-11-12
  • Java超详细讲解类的继承
    目录写在前面1.子类的创建1.1子类的创建方法1.2调用父类中特定的构造方法2.在子类中访问父类成员3.覆盖3.1覆盖父类中的方法3.2用父类的对象访问子类的成员4.不可被继承的成员...
    99+
    2022-11-13
  • 详细讲解Java抽象类示例
    目录Java抽象类概念Java抽象类示例继承Animal类的子类的示例Java抽象类详细使用方法1、定义抽象类2、继承抽象类3、实现抽象方法4、完整示例代码Java抽象类概念 Jav...
    99+
    2023-05-19
    Java 抽象 抽象类
  • Java 超详细讲解核心类Spring JdbcTemplate
    目录JdbcTemplate概述JdbcTemplate开发步骤JdbcTemplate快速入门Spring产生JdbcTemplate对象JdbcTemplate的常用操作修改操作...
    99+
    2022-11-10
  • Java超详细讲解ThreadLocal类的使用
    目录Threadlocal有什么用:ThreadLocal使用实例API介绍ThreadLocal的使用Threadlocal 的源码分析原理源码内部类ThreadLocalMapT...
    99+
    2022-11-13
  • Java超详细讲解类变量和类方法
    目录1.static静态变量2.类变量(静态变量的访问)3.类方法1.static静态变量 1.静态变量被同一个类的所有对象共享 2.static类变量在类加载的时候就生成使用 st...
    99+
    2022-11-13
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作