sunny123456

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  1796 随笔 :: 22 文章 :: 24 评论 :: 226万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

枚举类型的创建与使用

在实际编程中,存在着这样的“数据集”,它们的数值在程序中是稳定的并且个数是有限的。例如春、夏、秋、冬四个数据元素组成了四季的“数据集”,一月到十二月组成了十二个月份的“数据集”,周一到周五及周六周日组成了每周七天的“数据集”。在Java中可以使用枚举类型来表示这些数据。

在Java5之前,没有枚举类型,需要使用静态常量。如下:

public class Week {
    static final int SUNDAY = 0;
    static final int MONDAY = 1;
    static final int TUESDAY = 2;
    static final int WEDNESDAY = 3;
    static final int THURSDAY = 4;
    static final int FRIDAY = 5;
    static final int SATURDAY = 6;
}

要使用上面这些模拟的枚举值时,直接使用Week类名调用静态常量即可。不过这种方式可能会出现一个问题,当声明一个方法中接受int类型的参数时,也可以使用上面定义的静态常量作为实参传入,编译器不会报错,但是会影响代码的阅读性。

Java5开始新增了枚举类型,避免了上面的问题。定义枚举类型,使用enum关键字,声明格式如下:

[修饰符] enum 枚举名 {
    枚举成员
}

修饰符:public、private、internal。

枚举名:符合Java规范的标识符。

枚举成员:任意枚举成员之间不能有相同的名字,多个枚举成员之间使用逗号隔开,最后一个成员后面可以有分号,也可以没有。

下面代码定义了一个枚举类型Week,用该类型声明的变量只能存储枚举类型定义中给出的某个枚举值,或者null值。

public enum Week {
    Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday;
}

可以使用swith语句很方便地判断枚举的值,如下:

class WeekTest {
    static void UseWeek(Week day) {  // 使用Week枚举类型声明变量day
        switch (day) {
            case Sunday:
                System.out.println("星期天");
                break;
            case Monday:
                System.out.println("星期一");
                break;
            case Tuesday:
                System.out.println("星期二");
                break;
            case Wednesday:
                System.out.println("星期三");
                break;
            case Thursday:
                System.out.println("星期四");
                break;
            case Friday:
                System.out.println("星期五");
                break;
            case Saturday:
                System.out.println("星期六");
                break;
        }
    }
 
    public static void main(String[] args) {
        WeekTest.UseWeek(Week.Monday);   // 输出“星期一”
    }
}

枚举类型最常用的地方就是在switch语句中使用。上面的代码在UseWeek()方法中定义了一个形参day,其类型是Week枚举类型,将变量day作为swith语句的表达式,通过对day的值来配符case语句中的常量的值,若相等执行相应的case语句。

另外:case表达式中可以直接写入枚举值(写也可以),不用添加枚举类作为限定。

枚举的本质是类,只不过是使用enum关键字替代class,它所创建的类型都是java.lang.Enum类的子类,而java.lang.Enum是一个抽象类。枚举屏蔽了枚举值的类型信息,不像在用public static final 三个修饰符修饰的常量时必须指定类型。枚举是用来构建常量数据结构的模板,而且这个模板也可以扩展(添加属性、方法、构造函数)。

所以上面使用enum关键字创建的Week枚举,其源文件名是Week.java,编译后的文件名是Week.class,和类一样。

下面代码是使用JDK自带的javap工具来反编译Week.class文件,会输出如下的结果:

//PS D:\MyJavaLearn\> javap Week.class
//Compiled from "Week.java"
 
public final class com.test.Week extends java.lang.Enum<Week> {
  public static final Week Sunday;
  public static final Week Monday;
  public static final Week Tuesday;
  public static final Week Wednesday;
  public static final Week Thursday;
  public static final Week Friday;
  public static final Week Saturday;
  public static Week[] values();
  public static Week valueOf(java.lang.String);
  static {};

从上面反编译的代码可以看出,枚举类型实际上还是一个类,枚举值还是静态常量,使用public static final 三个修饰符。但是,这些常量的类型就是类本身。

从反编译的代码中还可以看到Week类增加了两个静态方法values()和valueOf()。

在Java语言中,每一个枚举类型成员都可以当做一个Enum类的实例。而且枚举成员会默认被public static final修饰,所以可以直接使用枚举名调用它。

java.lang.Enum类是一个抽象类,所有创建的枚举类型自动实现了它,故所有枚举实例都可以调用枚举类定义的方法。常用的如下:

枚举常用方法
方法名说明
compareTo比较枚举与指定对象的定义顺序
valueOf(Class<T>enumType,String name)返回带指定名称的指定枚举类型的枚举常量
values()以数组的形式返回枚举类型的所有成员
ordinal()返回枚举常量的索引位置(它在枚举声明中的位置,其中初始常量序数为零
toString()返回枚举常量的名称

下面代码定义了一个颜色枚举类型,使用了如上方法的调用。

public class EnumMethod {
    // 定义颜色枚举类
    public enum Color {
        red,yellow,green,blue,pink,brown,purple
    }
 
    public static void main(String[] args) {
        // ordinal()方法的使用:获取指定枚举实例的索引
        for (int i=0;i<Color.values().length;i++) {
            // 循环输出枚举类中所有枚举常量的索引值
            System.out.print(Color.values()[i] + "的索引:" + Color.values()[i].ordinal() + "  ");
        }
 
        System.out.println();
 
        // toString()方法的使用,返回枚举常量的名称
        System.out.println("toString()方法的使用:" + Color.blue.toString());
        // compareTo()方法的使用
        System.out.println("compareTo()方法的使用:" + Color.blue.compareTo(Color.red));
        // valueOf()方法使用
        System.out.println("valueOf方法使用:" + Color.valueOf("green"));
    }
}

输出的结果如下:

 为枚举添加属性和方法

枚举类型出来Java提供的方法,还可以定义自己的方法。但需要注意,这时需要在枚举实例的最后一个成员后面添加分号,并且必须先定义枚举实例。如下代码:

package com.test;
 
public enum EnumProperty {
    // 枚举成员定义,且必须以分好结尾
    Jan("January"),Feb("February"),Mar("March"),Apr("April"),May("May"),Jun("June"),
    Jul("July"),Aug("August"),Sep("September"),Oct("October"),Nov("November"),Dec("December");
 
    // 定义枚举类型的private属性
    private final String month;
 
    // 定义私有构造函数(也可以是public)
    private EnumProperty(String month) {
        this.month = month;
    }
 
    // 定义枚举类的public方法
    public String getMonth(){
        return month;
    }
}
 
class EnumPropertyTest {
    public static void main(String[] args) {
        // 使用for循环遍历枚举类型,并输出
        for(EnumProperty en :EnumProperty.values()) {
            System.out.println(en + " : " + en.getMonth());
        }
    }
}

上面代码定义了EnumPropery枚举,声明了它的私有属性month和私有构造方法EnumPropery(),及public方法getMonth()。构造方法EnumPropery()作用是为私有属性month赋值,getMonth()方法是获取私有属性month的值。在上面的测试类中,通过枚举的values()方法获得枚举的所有成员,再通过for循环遍历成员,其中调用自定义的方法getMonth()获取枚举的成员。

请注意:在定义枚举成员时的Jan("January"),其实是调用了构造函数,并传入“January”进行初始化枚举的私有属性month,给其进行赋值“January”。

枚举值的比较

如果只是简单地比较两个枚举类型的值是否相等,那么直接使用比较运算符“==”即可。如果需要进一步地比较,则可以使用枚举值的compareTo方法。

枚举的对象有一个ordinal()方法可以获取枚举值的一个数值表示,compareTo()方法实际是比较两个值的ordinal的值。比如如下代码:

System.out.println(Week.Monday.compareTo(Week.Thursday));

上面代码运行的结果是:-3

使用compareTo()方法比较两个枚举值,当结果小于0时,compareTo左边的枚举值小于右边的枚举值;当结果为0时,则说明两个枚举值相等;当结果大于0时,则说明compareTo左边的枚举值大。

注意:Java中,不允许使用“>”和“<”比较运算符比较两个枚举值。

另外:自定义的比较方法不能取名为compareTo,因为所有枚举类型生产的类都是从Enum类继承的,而Enum类中的compareTo方法不能被覆盖。

EnumSet和EnumMap类

为了更高效地操作枚举类型,java.util中有EnumSet和EnumMap两个类。

1)EnumMap类

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

2)EnumSet类

EnumSet类是枚举类型的高性能Set实现。EnumSet要求放入它的枚举常量必须属于同一枚举类型,它提供了许多工厂方法以便于初始化。

EnumSet常用方法
方法说明
allOf(Class<E>elementType) 

创建一个包含指定枚举类型的所有枚举成员的EnumSet对象

complementOf(EnumSet<E> s)创建一个与指定枚举类型对象s相同的EnumSet对象,包含指定s中不包含的枚举成员
copyOf(EnumSet<E> s)创建一个与指定枚举类型对象s相同的EnumSet对象,包含与s中相同的枚举成员
noneOf(Class<E>elementType) 创建一个具有指定枚举类型的空EnumSet对象
of(E first,E... rest)创建一个包含指定枚举成员的EnumSet对象
range(E from,E to)创建一个包含从from到to的所有枚举成员的EnumSet对象

package com.test;
import java.util.*;
import java.util.Map.Entry;
 
enum EnumMonth {
    Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Noe,Dec
}
 
public class EnumTest {
    public static void main(String[] args) {
        // EnumSet的使用
        EnumSet<EnumMonth> monthSet = EnumSet.allOf(EnumMonth.class);
        for (EnumMonth month : monthSet) {
            System.out.print(month + "  ");
        }
        System.out.println();
 
        // EnumMap的使用
        EnumMap<EnumMonth,String> monthMap = new EnumMap(EnumMonth.class);
        monthMap.put(EnumMonth.Jan,"一月份");
        monthMap.put(EnumMonth.Feb,"二月份");
        monthMap.put(EnumMonth.Mar,"三月份");
        monthMap.put(EnumMonth.Apr,"四月份");
        monthMap.put(EnumMonth.May,"五月份");
        monthMap.put(EnumMonth.Jun,"六月份");
        // 省略了7-12月份
        for (Iterator<Entry<EnumMonth,String>> ite=monthMap.entrySet().iterator();ite.hasNext();) {
            Entry<EnumMonth,String> entry = ite.next();
            System.out.print(entry.getKey().name() + ":" + entry.getValue() + "  ");
        }
    }
}

运行的结果如下:

上面代码,通过EnumSet的allOf()方法获得枚举类EnumMonth的所有枚举成员,并通过for循环打印输出所有的枚举成员。

对于EnumMap的使用,是通过其构造方法返回一个指定枚举类型的空的枚举映射monthMap,再通过它的put()方法将枚举成员依次添加到这个空枚举映射monthMap变量中。然后通过迭代器Itertor和for循环依次将EnumMap的键-值打印出来。

原文链接:https://blog.csdn.net/2303_79232676/article/details/136833113
posted on   sunny123456  阅读(41)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2020-12-16 分页总数计算,根据总条数和每页条数获取总页数
点击右上角即可分享
微信分享提示