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,可以进行快速检索。






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


相关文章
|
1月前
|
Java 开发者
在 Java 中,一个类可以实现多个接口吗?
这是 Java 面向对象编程的一个重要特性,它提供了极大的灵活性和扩展性。
153 57
|
7天前
|
JSON Java Apache
Java基础-常用API-Object类
继承是面向对象编程的重要特性,允许从已有类派生新类。Java采用单继承机制,默认所有类继承自Object类。Object类提供了多个常用方法,如`clone()`用于复制对象,`equals()`判断对象是否相等,`hashCode()`计算哈希码,`toString()`返回对象的字符串表示,`wait()`、`notify()`和`notifyAll()`用于线程同步,`finalize()`在对象被垃圾回收时调用。掌握这些方法有助于更好地理解和使用Java中的对象行为。
|
1月前
|
安全 Java 测试技术
🎉Java零基础:全面解析枚举的强大功能
【10月更文挑战第19天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
121 60
|
1月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
52 24
|
1月前
|
存储 缓存 安全
java 中操作字符串都有哪些类,它们之间有什么区别
Java中操作字符串的类主要有String、StringBuilder和StringBuffer。String是不可变的,每次操作都会生成新对象;StringBuilder和StringBuffer都是可变的,但StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此性能略低。
56 8
|
1月前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
74 17
|
1月前
|
安全 Java
Java多线程集合类
本文介绍了Java中线程安全的问题及解决方案。通过示例代码展示了使用`CopyOnWriteArrayList`、`CopyOnWriteArraySet`和`ConcurrentHashMap`来解决多线程环境下集合操作的线程安全问题。这些类通过不同的机制确保了线程安全,提高了并发性能。
|
1月前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
135 4
|
1月前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
80 2
|
1月前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
62 4