Java学习笔记 15、枚举类

简介: Java学习笔记 15、枚举类

一、认识枚举类


当类的对象只有有限个,确定的时,并且需要将其对象定义为一组常量时,建议使用枚举类,若枚举类只有一个对象则可以作为一种单例模式的实现方式。


举例:JDK中的Tread.State类中使用了枚举类,有NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED,它们分别用来表示线程的不同状态。

枚举类可以使用两种方式实现:


JDK1.5之前需要自定义枚举类。

JDK 1.5 新增 enum关键字来用于定义枚举类。


二、自定义枚举类(jdk1.5之前方式)


枚举类的属性介绍:


枚举类对象的属性不应该进行改动,应使用private final(常量)来修饰。

对于使用private final的常量对象应该在有参构造器中进行赋值。

自定义枚举类如下:


class Season{
    //1、将注解类中的属性设置为private final常量,不能进行改动
    private final String SeasonName;
    private final String SeasonDesc;
    //2、私有构造器,防止外部构造对象
    private Season(String seasonName, String seasonDesc) {
        SeasonName = seasonName;
        SeasonDesc = seasonDesc;
    }
    public String getSeasonName() {
        return SeasonName;
    }
    public String getSeasonDesc() {
        return SeasonDesc;
    }
    @Override
    public String toString() {
        return "Season{" +
                "SeasonName='" + SeasonName + '\'' +
                ", SeasonDesc='" + SeasonDesc + '\'' +
                '}';
    }
    //3、提供当前枚举类的多个对象,其修饰符为:public static final,可以被外界获取
    public static final Season SPRING = new Season("春天","百花齐放");
    public static final Season SUMMER = new Season("夏天","夏日炎炎");
    public static final Season AUTUMN = new Season("秋天","秋高气爽");
    public static final Season WINTER = new Season("冬天","白雪皑皑");
}
/**
 * @ClassName EnumExer
 * @Author ChangLu
 * @Date 2021/2/21 15:50
 * @Description TODO
 */
public class EnumExer {
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        Season summer = Season.SUMMER;
        Season autumn = Season.AUTUMN;
        Season winter = Season.WINTER;
        System.out.println(spring);//Season{SeasonName='春天', SeasonDesc='百花齐放'}
        System.out.println(summer);//Season{SeasonName='夏天', SeasonDesc='夏日炎炎'}
        System.out.println(autumn);//Season{SeasonName='秋天', SeasonDesc='秋高气爽'}
        System.out.println(winter);//Season{SeasonName='冬天', SeasonDesc='白雪皑皑'}
    }
}


注意其中三个关键点

第一个就是属性应该设置为private final是不允许外界使用set方法进行赋值的。

第二个就是构造器为private,外界不能通过构造器来构造枚举类对象。

第三个就是提供枚举类对象,权限修饰符为public static final 应该是能够被外界直接获取使用的。

这是自定义枚举类的方式,一般我们使用jdk1.5之后的这种方式来创建枚举类。



三、enum定义枚举类(jdk1.5新增)


3.1、使用enum定义枚举类


使用enum定义的枚举类说明:


使用enum定义的枚举类默认继承了java.lang.Enum类,因此不能继承其他类。

枚举类的构造器只能使用private权限修饰符。

枚举类实例在类中显示列出,使用,分割;结尾,可定义多个实例。列出的实例系统会自动添加public static final修饰。

必须在枚举类的第一行声明枚举类对象。

JDK 1.5 中可以在 switch 表达式中使用Enum定义的枚举类的对象作为表达式, case 子句可以直接使用枚举值的名字, 无需添加枚举类作为限定。

enum定义枚举类如下:


enum Season{
    //,分割  ;结尾   这里实际上定义了4个public static final的实例(会自动添加修饰)
 //SPRING("春天","百花齐放")  =>(相当于)  public static final Season SPRING = new Season("春天","百花齐放");
    SPRING("春天","百花齐放"),
    SUMMER("夏天","夏日炎炎"),
    AUTUMN("秋天","秋高气爽"),
    WINTER("冬天","白雪皑皑");
    private final String SeasonName;
    private final String SeasonDesc;
    private Season(String seasonName, String seasonDesc) {
        SeasonName = seasonName;
        SeasonDesc = seasonDesc;
    }
    public String getSeasonName() {
        return SeasonName;
    }
    public String getSeasonDesc() {
        return SeasonDesc;
    }
}
public class EnumExer {
    public static void main(String[] args) {
        Season spring = Season.SPRING;
        Season summer = Season.SUMMER;
        Season autumn = Season.AUTUMN;
        Season winter = Season.WINTER;
        System.out.println(spring);//SPRING
        System.out.println(summer);//SUMMER
        System.out.println(autumn);//AUTUMN
        System.out.println(winter);//WINTER
    }
}


使用enum定义时,对于实例需要直接写在类的最前面,若是有多个实例可以使用,分割开。

这里输出时使用的是Enum类中的toString()输出的是当前枚举常量的名称。


3.2、认识java.lang.enum类


之前说到使用enum定义枚举类的会继承java.lang.enum,看一下该类:



实现了Comparable接口以及序列化接口。



static static <T extends Enum<T>> T valueOf():传递枚举类型的Class对象和枚举常量名称,会得到与参数匹配的枚举常量。

String toString():默认会得到当前枚举常量的名称。可以通过重写这个方法来使得到的结果更易读。

final boolean equals():该方法是常量(final)方法无法重写,在Enum中是使用==来比较两个枚举常量是否相同。其存在是为了在Set、List和Map中使用。

final int hashCode():与equals()同样是常量方法无法被子类重写。

final Class<E> getDeclaringClass():得到枚举常量所属枚举类型的Class对象。可以用它来判断两个枚举常量是否属于同一个枚举类型。

final String name():也是得到当前枚举常量的名称,与toString()都是返回name属性。

final int ordinal():得到当前枚举常量定义时的序列号(从0开始)。

final int compareTo():这是实现Comparable接口的方法,来比较两个枚举常量的大小(根据定义实例的声明顺序排列)。

final Object clone():因枚举类型不能被克隆,防止子类实现克隆方法,该方法定义为常量方法,并且直接抛出CloneNotSupportedException异常。

常用方法介绍:前两个是编译器插入到enum中的方法并不是默认继承Enum类获取的方法


values():该方法是编译器插入到enum定义中的static方法,直接调用枚举类的方法,返回一个你定义的枚举类数组,方便进行遍历该枚举类的常量。

valueOf(String str):通过传入一个字符串来获取该枚举类的一个枚举实例,必须是枚举类对象的实例名称,否则IllegalArgumentException异常。

toString():这是继承Enum类的方法,返回实例名称,尽量要重写它。

提出疑问这两个方法是怎么来的?


查阅博客,通过反编译字节码文件认为是实现了java.lang.annotation.ElementType中的values()与valueOf方法,这个过程是在编译器中自动生成的。

测试编译器中生成的两个方法:


enum Code{
    RED,BLUE,YELLOW;
}
public class Test {
    public static void main(String[] args) {
        //测试Code枚举类的values()方法
        Code[] values = Code.values();
        for (Code value : values) {
            System.out.println(value);
        }
        //RED
        //BLUE
        //RED
        //测试valueOf()方法
        System.out.println(Code.valueOf("RED"));//RED
    }
}




IDEA中悬浮到这两个方法时的介绍。

我们自己进行反编译字节码查看一下下面这个枚举类


enum Code{
    RED,BLUE,YELLOW;
}


首先使用javac 类.java编译成字节码文件(.class后缀),之后使用javap Code进行反编译该字节码文件:



之后再使用javap -v Code来查看Code.class字节码结构:




这里看到是继承的Enum,查阅大佬博客推测出实际上是继承了ElementType,我们去看一下Enum类的定义


//这里泛型为E extends Enum<E> 表示该泛型必须是Enum的子类
public abstract class Enum<E extends Enum<E>>



ElementType是注解,并且是Enum类的子类。



参考博客: Java中Enum类下的values()方法的由来

先暂且这么记着,对于我现在的水平不能窥探到更深的地步,日后再来深入挖掘。



3.3、枚举类实现接口


现有一个接口如下:


interface Info{
    void show();
}


直接在enum枚举类中实现抽象方法


//实现该接口
enum Season implements Info{
    SPRING("春天","百花齐放"),
    SUMMER("夏天","夏日炎炎"),
    AUTUMN("秋天","秋高气爽"),
    WINTER("冬天","白雪皑皑");
    private String SeasonName;
    private String SeasonDesc;
    private Season(String seasonName, String seasonDesc) {
        SeasonName = seasonName;
        SeasonDesc = seasonDesc;
    }
  //直接实现抽象方法show()
    @Override
    public void show() {
        System.out.println("这里是描述四个季节的枚举类");
    }
}
public class EnumExer {
    public static void main(String[] args) {
        Season.SPRING.show();//这里是描述四个季节的枚举类
        Season.SUMMER.show();//这里是描述四个季节的枚举类
    }
}



可以看到多个实例调用的都是同一个show()方法。

枚举类中实例重写show()方法


enum Season implements Info{
    //这里对该实例进行了方法重写(应该是重写了Season该类的show()方法)
    SPRING("春天","百花齐放"){
        @Override
        public void show() {
            System.out.println("SPRING实例的show()方法调用了....");
        }
    },
    SUMMER("夏天","夏日炎炎"){
        @Override
        public void show() {
            System.out.println("SUMMER实例的show()方法调用了....");
        }
    },
    AUTUMN("秋天","秋高气爽"),
    WINTER("冬天","白雪皑皑");
    private String SeasonName;
    private String SeasonDesc;
    private Season(String seasonName, String seasonDesc) {
        SeasonName = seasonName;
        SeasonDesc = seasonDesc;
    }
    @Override
    public void show() {
        System.out.println("这里是描述四个季节的枚举类");
    }
}
public class EnumExer {
    public static void main(String[] args) {
        Season.SPRING.show();//SPRING实例的show()方法调用了....
        Season.SUMMER.show();//SUMMER实例的show()方法调用了....
        Season.AUTUMN.show();//这里是描述四个季节的枚举类
    }
}


可以看到这里是在对应实例后添加{},其中重写了show()方法,之后我们调用实例的方法就是指定其重写的方法。

总结:


枚举类可以实现一个或多个接口,统一实现方法每个枚举实例都可以进行调用。

继承接口方式的使用方法有如上两种方式。


四、enum相关的类


Class类与enum相关



isEnum():能够判断该Class是否为枚举类。


与enum相关的工具类:EnumSet与EnumMap


EnumSet:JDK1.5引入,该类设计充分考虑了速度因素,可以作为Enum的替代者,效率更高。


EnumMap:JDK1.5引入,是一个特殊的Map,其key键是一个enum,可以进行快速检索。






暂且就先记录一下,深入使用内容后序若是使用到了进行补充。


相关文章
|
23小时前
|
Java
类信息的“隐形守护者”:JAVA反射技术全揭秘
【7月更文挑战第1天】Java反射技术是动态获取类信息并操作对象的强大工具。它基于Class对象,允许在运行时创建对象、调用方法和改变字段。例如,通过`Class.forName()`动态实例化对象,`getMethod()`调用方法。然而,反射可能破坏封装,影响性能,并需处理异常,故使用时需谨慎。它是Java灵活性的关键,常见于框架设计中。
6 0
|
1天前
|
Java 容器
Java中使用Optional类的建议
Java中使用Optional类的建议
|
1天前
|
存储 安全 Java
Java详解 : 单列集合 | 双列集合 | Collections类
Java详解 : 单列集合 | 双列集合 | Collections类
|
1天前
|
Java
Java中的Object类 ( 详解toString方法 | equals方法 )
Java中的Object类 ( 详解toString方法 | equals方法 )
|
1天前
|
安全 Java 索引
带你快速掌握Java中的String类和StringBuffer类(详解常用方法 | 区别 )
带你快速掌握Java中的String类和StringBuffer类(详解常用方法 | 区别 )
|
1天前
|
Java 索引
Java中的Arrays类
Java中的Arrays类
|
1天前
|
Java
Calendar类在Java中的高级应用与使用技巧
Calendar类在Java中的高级应用与使用技巧
|
1天前
|
安全 Java 开发者
Calendar类在Java中的高级应用与使用技巧
Calendar类在Java中的高级应用与使用技巧
|
2天前
|
开发框架 Java
JAVA反射:揭秘!运行时如何窥探类的秘密?
【6月更文挑战第30天】Java反射是运行时检查类信息并动态操作对象的机制。通过`Class`对象,我们可以访问私有成员,如在Person类示例中设置私有变量name和调用方法。反射增加了代码灵活性,常用于动态类型、插件和框架设计。
|
2天前
|
Java
Java中Integer类的应用
Java中Integer类的应用