【JavaSE学习笔记】枚举类

本文详细介绍了Java SE中的枚举类,包括其定义、原理、常用方法以及如何实现抽象方法和接口。通过实例演示了如何利用EnumMap和EnumSet优化枚举操作,并讨论了它们在实际项目中的应用场景和优势。
摘要由CSDN通过智能技术生成

JavaSE枚举类

一、什么是枚举类

​ 枚举类型是Java 5中新增特性的一部分,它是一种特殊的数据类型,允许用常量来表示特定的数据片段,特殊是因为它既是一种类(class)类型却又比类类型多了些特殊的约束,但是这些约束的存在也造就了枚举类型的简洁性、安全性以及便捷性。

二、如何定义枚举类

1、自定义枚举类

首先来想一下如果没有枚举类,我们如何自己实现一个。

public class Gvim4Java20210418{
    public static void main(String[] args){
        System.out.println(Season.SPRING);
    }
}

class Season{
	public static Season SPRING = new Season("春天");

	private final String seasonName;
    
    private Season(String seasonName){
        this.seasonName = seasonName;
	}
    
    public String toString(){
        return this.seasonName;
    }
}

2、使用enum关键字定义枚举类

再看Java中的枚举类定义。

public class Gvim4Java20210418{
    public static void main(String[] args){
        System.out.println(Season.SPRING);
        System.out.println(Season.SUMMER);
    }
}

enum Season{
    SUMMER("夏天"),SPRING("春天");

	private String seasonName;

    private Season(String seasonName){
        this.seasonName = seasonName;
    }
}

三、枚举类实现原理

​ 通过上面简单的代码示例,我们定义了枚举类,一个是自定义的,一个是使用enum关键字定义的。乍一看俩者似乎没有什么区别,其实有着极大的不同。接下来深入探究枚举类实现原理。

参考博客地址:https://blog.csdn.net/javazejian/article/details/71333103

1、定义一个枚举类

enum Day {
    MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

2、反编译查看生成的源代码文件

//反编译Day.class
final class Day extends Enum
{
    //编译器为我们添加的静态的values()方法
    public static Day[] values()
    {
        return (Day[])$VALUES.clone();
    }
    //编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
    public static Day valueOf(String s)
    {
        return (Day)Enum.valueOf(com/zejian/enumdemo/Day, s);
    }
    //私有构造函数
    private Day(String s, int i)
    {
        super(s, i);
    }
     //前面定义的7种枚举实例
    public static final Day MONDAY;
    public static final Day TUESDAY;
    public static final Day WEDNESDAY;
    public static final Day THURSDAY;
    public static final Day FRIDAY;
    public static final Day SATURDAY;
    public static final Day SUNDAY;
    private static final Day $VALUES[];

    static 
    {    
        //实例化枚举实例
        MONDAY = new Day("MONDAY", 0);
        TUESDAY = new Day("TUESDAY", 1);
        WEDNESDAY = new Day("WEDNESDAY", 2);
        THURSDAY = new Day("THURSDAY", 3);
        FRIDAY = new Day("FRIDAY", 4);
        SATURDAY = new Day("SATURDAY", 5);
        SUNDAY = new Day("SUNDAY", 6);
        $VALUES = (new Day[] {
            MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
        });
    }
}

​ 实际上在使用关键字enum创建枚举类型并编译后,编译器会为我们生成一个相关的类,这个类继承了Java API中的java.lang.Enum类,也就是说通过关键字enum创建枚举类型在编译后事实上也是一个类类型而且该类继承自java.lang.Enum类。

​ 总结生成的类特点如下:

​ 1、继承自java.lang.Enum

​ 2、编译器生成的类被final关键字标识。

​ 3、包含一个私有构造器。

​ 4、有俩个静态方法,values方法和valueOf方法,其中valueOf方法调用了Enum类中的valueOf方法。

​ 5、生成了相应枚举类对象的实例和一个包含所有元素的数组。

四、Enum抽象类类常用方法

Enum类内部会有一个构造函数,该构造函数只能有编译器调用,我们是无法手动操作的。

1、方法表

返回类型方法签名作用
intcompareTo(E e)比较枚举类声明的顺序。
booleanequals(Object other)比较枚举类是否相等。
Class<?>getDeclaringClass()返回与此枚举常量的枚举类型相对应的 Class 对象。
Stringname()返回此枚举常量的名称,在其枚举声明中对其进行声明。
intordinal()返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
StringtoString()返回枚举常量的名称,它包含在声明中。
<T extends Enum<T>> Tstatic valueOf(Class<T> enumType, String name)返回带指定名称的指定枚举类型的枚举常量。

2、方法测试

import java.util.Arrays;

public class App {
    public static void main(String[] args) {
        Day[] days = { 
            Day.MONDAY, 
            Day.TUESDAY, 
            Day.WEDNESDAY, 
            Day.THURSDAY, 
            Day.FRIDAY, 
            Day.SATURDAY, 
            Day.SUNDAY
        };

        System.out.println("----------------------------------------------------");
        for (int i = 0; i < days.length; i++) {
            System.out.print("day[" + i + "].name() = " + days[i].name() + " -> ");
            System.out.println("day[" + i + "].ordinal() = " + days[i].ordinal());
        }

        System.out.println("----------------------------------------------------");
        System.out.println("day[0].compareTo(day[1]) = " + days[0].compareTo(days[1]));
        System.out.println("day[1].compareTo(day[0]) = " + days[1].compareTo(days[0]));

        System.out.println("----------------------------------------------------");
        Class<?> clazz = days[0].getDeclaringClass();
        System.out.println("clazz: " + clazz);

        System.out.println("----------------------------------------------------");
        for (int i = 0; i < days.length; i++) {
            System.out.println("day[" + i + "].toString() = " + days[i].toString());
        }

        System.out.println("----------------------------------------------------");
        System.out.println(Day.valueOf(Day.class, "MONDAY"));
        System.out.println("----------------------------------------------------");
    }
}

enum Day {
    MONDAY("monday", 0), 
    TUESDAY("tuesday", 1), 
    WEDNESDAY("wednesday", 2), 
    THURSDAY("thursday", 3), 
    FRIDAY("friday", 4),
    SATURDAY("saturday", 5), 
    SUNDAY("sunday", 6);

    private String name;
    private int value;

    private Day(String name, int value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return this.name;
    }

    public int getValue() {
        return this.value;
    }
}

测试结果:

----------------------------------------------------
day[0].name() = MONDAY -> day[0].ordinal() = 0
day[1].name() = TUESDAY -> day[1].ordinal() = 1
day[2].name() = WEDNESDAY -> day[2].ordinal() = 2
day[3].name() = THURSDAY -> day[3].ordinal() = 3
day[4].name() = FRIDAY -> day[4].ordinal() = 4
day[5].name() = SATURDAY -> day[5].ordinal() = 5
day[6].name() = SUNDAY -> day[6].ordinal() = 6
----------------------------------------------------
day[0].compareTo(day[1]) = -1
day[1].compareTo(day[0]) = 1
----------------------------------------------------
clazz: class Day
----------------------------------------------------
day[0].toString() = MONDAY
day[1].toString() = TUESDAY
day[2].toString() = WEDNESDAY
day[3].toString() = THURSDAY
day[4].toString() = FRIDAY
day[5].toString() = SATURDAY
day[6].toString() = SUNDAY
----------------------------------------------------
Day.valueOf(Day.class, 'MONDAY') = MONDAY
----------------------------------------------------

五、编译器生成方法

1、方法解析

在反编译的源码文件中可以看到,有俩个方法是没有在Enum类中出现的:

public static Day[] values()

public static Day valueOf(String s)

在Enum类中并没出现values()方法,但valueOf()方法还是有出现的,只不过编译器生成的valueOf()方法需传递一个name参数,而Enum自带的静态方法valueOf()则需要传递两个方法,从前面反编译后的代码可以看出,编译器生成的valueOf方法最终还是调用了Enum类的valueOf方法。

2、方法测试

import java.util.Arrays;

public class App {
    public static void main(String[] args) {
        System.out.println("Day.values() -> " + Arrays.toString(Day.values()));

        System.out.println(
            "Day.valueOf('MONDAY').getName() -> " + Day.valueOf("MONDAY").getName()
        );
    }
}

enum Day {
    MONDAY("monday", 0), 
    TUESDAY("tuesday", 1), 
    WEDNESDAY("wednesday", 2), 
    THURSDAY("thursday", 3), 
    FRIDAY("friday", 4),
    SATURDAY("saturday", 5), 
    SUNDAY("sunday", 6);

    private String name;
    private int value;

    private Day(String name, int value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return this.name;
    }

    public int getValue() {
        return this.value;
    }
}

测试结果

Day.values() -> [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
Day.valueOf('MONDAY').getName() -> monday

六、enum类中定义抽象方法以及实现接口

1、enum类中定义抽象方法

​ 与常规抽象类一样,enum类允许我们为其定义抽象方法,然后使每个枚举实例都实现该方法,以便产生不同的行为方式,注意abstract关键字对于枚举类来说并不是必须

public class App {
    public static void main(String[] args) {
        Day.FRIDAY.absMethod();
        Day.MONDAY.absMethod();
    }
}

enum Day {
    MONDAY("monday", 0){
        public void absMethod(){
            System.out.println("monday absMethod");
        }
    }, 
    TUESDAY("tuesday", 1){
        public void absMethod(){
            System.out.println("tuesday absMethod");
        }
    },  
    WEDNESDAY("wednesday", 2){
        public void absMethod(){
            System.out.println("wednesday absMethod");
        }
    },   
    THURSDAY("thursday", 3){
        public void absMethod(){
            System.out.println("thursday absMethod");
        }
    },   
    FRIDAY("friday", 4){
        public void absMethod(){
            System.out.println("friday absMethod");
        }
    },   
    SATURDAY("saturday", 5){
        public void absMethod(){
            System.out.println("saturday absMethod");
        }
    },   
    SUNDAY("sunday", 6){
        public void absMethod(){
            System.out.println("sunday absMethod");
        }
    };

    private String name;
    private int value;

    private Day(String name, int value) {
        this.name = name;
        this.value = value;
    }

    public abstract void absMethod();

    public String getName() {
        return this.name;
    }

    public int getValue() {
        return this.value;
    }
}

测试结果:

friday absMethod
monday absMethod

2、enum类实现接口

​ enum类可以实现多接口

public class App {
    public static void main(String[] args) {
        Day.FRIDAY.functionMethod();
        Day.MONDAY.functionMethod();
    }
}

enum Day implements Function{
    MONDAY("monday", 0){
        public void functionMethod(){
            System.out.println("monday functionMethod");
        }
    }, 
    TUESDAY("tuesday", 1){
        public void functionMethod(){
            System.out.println("tuesday functionMethod");
        }
    },  
    WEDNESDAY("wednesday", 2){
        public void functionMethod(){
            System.out.println("wednesday functionMethod");
        }
    },   
    THURSDAY("thursday", 3){
        public void functionMethod(){
            System.out.println("thursday functionMethod");
        }
    },   
    FRIDAY("friday", 4){
        public void functionMethod(){
            System.out.println("friday functionMethod");
        }
    },   
    SATURDAY("saturday", 5){
        public void functionMethod(){
            System.out.println("saturday functionMethod");
        }
    },   
    SUNDAY("sunday", 6){
        public void functionMethod(){
            System.out.println("sunday functionMethod");
        }
    };

    private String name;
    private int value;

    private Day(String name, int value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return this.name;
    }

    public int getValue() {
        return this.value;
    }
}

interface Function{
    void functionMethod();
}

测试结果

friday functionMethod
monday functionMethod

七、Enum相关集合

1、EnumMap

​ EnumMap要求其Key必须为Enum类型,因而使用Color枚举实例作为key是最恰当不过了,也避免了获取name的步骤,更重要的是EnumMap效率更高,因为其内部是通过数组实现的(稍后分析),注意EnumMap的key值不能为null,虽说是枚举专属集合,但其操作与一般的Map差不多,概括性来说EnumMap是专门为枚举类型量身定做的Map实现,虽然使用其它的Map(如HashMap)也能完成相同的功能,但是使用EnumMap会更加高效,它只能接收同一枚举类型的实例作为键值且不能为null,由于枚举类型实例的数量相对固定并且有限,所以EnumMap使用数组来存放与枚举类型对应的值,毕竟数组是一段连续的内存空间,根据程序局部性原理,效率会相当高。因为EnumMap是一种特殊的Map,所以支持Map的操作。

public class App {
    public static void main(String[] args) {
        Map<Color, Integer> enumMap = new EnumMap<>(Color.class);
        enumMap.put(Color.RED, 1);

        System.out.println(enumMap);
    }
}

enum Color {
    RED,BLUE,YELLOW
}

2、EnumSet

​ EnumSet是与枚举类型一起使用的专用 Set 集合,EnumSet 中所有元素都必须是枚举类型。与其他Set接口的实现类HashSet/TreeSet(内部都是用对应的HashMap/TreeMap实现的)不同的是,EnumSet在内部实现是位向量,它是一种极为高效的位运算操作,由于直接存储和操作都是bit,因此EnumSet空间和时间性能都十分可观,足以媲美传统上基于 int 的“位标志”的运算,重要的是我们可像操作set集合一般来操作位运算,这样使用代码更简单易懂同时又具备类型安全的优势。注意EnumSet不允许使用 null 元素。试图插入 null 元素将抛出 NullPointerException,但试图测试判断是否存在null 元素或移除 null 元素则不会抛出异常,与大多数collection 实现一样,EnumSet不是线程安全的,因此在多线程环境下应该注意数据同步问题。

​ EnumSet不像其他Set一样可以直接构造,而是提供了静态工厂方法来获取实例对象。

public class App {
    public static void main(String[] args) {
        // 创建包含枚举类中所有元素的集合
        EnumSet<Color> set = EnumSet.allOf(Color.class);
        System.out.println(set);
        // 创建不在枚举类不包含的元素的集合
        EnumSet<Color> set2 = EnumSet.noneOf(Color.class);
        System.out.println(set2);
        // 创建指定元素组成的枚举类的集合 可变参数列表
        EnumSet<Color> set3 = EnumSet.of(Color.RED);
        System.out.println(set3);
        // 创建指定元素开始到指定元素结尾的元素组成的集合 顺序由声明顺序决定
        EnumSet<Color> set4 = EnumSet.range(Color.RED, Color.YELLOW);
        System.out.println(set4);
        // 创建对应集合的补集
        EnumSet<Color> set5 = EnumSet.complementOf(set3);
        System.out.println(set5);
    }
}

enum Color {
    RED,BLUE,YELLOW
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值