Java 枚举

2021年10月11日,最近有点忙...说好要好好学习😥 每天10点学习两小时的我又:咕咕了🕊...

本人学习主要来源于尚硅谷 个人源码地址

Java 枚举

枚举 enum

什么是枚举类:

Java 枚举是一个特殊的类,一般表示一组常量

  • 比如: 一年的 4 个季节,一个年的 12 个月份,一个星期的 7 天,方向有东南西北等...

  • 类似这种当一个变量有几种固定可能的取值时, 可以将它定义为枚举类型

出现:

  • Java1.5 之前是没有 枚举注解 的.
  • 那时候一般用接口常量来替代 而使用 Java 枚举类型 enum 可以更贴近地表示这种常量. 还可以配合 Switch使用...

枚举类的实现:

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

  • JDK 1.5 新增的 enum 关键字用于定义枚举类.

  • 若枚举只有一个对象, 则可以作为一种单例模式的实现方式.

1.5之前 自定义实现枚举类:

  • 私有化类的构造器,保证不能在类的外部创建其对象
  • 在类的内部创建枚举类的实例,声明为: public static final 确保对象不会更改~
  • 对象如果有实例变量,应该声明为: private final 通过构造器初始化

SeasonTest1.Java

**`Season.Java`**
package com.wsm;
/**
 * 自定义枚举类学习 Season季节: 一年有四个季节是固定是刚好用来做枚举类
 */
public class SeasonTest1 {
    public static void main(String[] args) {
        //春天
        Season chu = Season.SPRING;
        System.out.println(chu.toString());
        /**
         * ok,这就是自定义枚举类, 类的对象是有固定个数的!且不可更改, 救像一种规则固定的对象...
         *      常用于规则状态的定义: 商品: 缺货 代发货 待付款...等固定的状态;
         * */
    }
}

class Season{
    //1.私有化类的构造器,并给对象属性赋值: 如果有对象属性的话顺便给属性赋值~
    private Season(String seasonName,String seasonDesc){
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    //2.声明Season对象的属性:private final修饰,因为枚举对象是固定的不能更改的.
    private final String seasonName;
    private final String 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("冬天","冰天雪地");

    //ok,到这儿,自定义的枚举类就创建好了
    //如果还有其它需求可以进行扩展... 创建方法:

    /** 获取枚举类对象的属性 */
    /** 常量只有get(); 方法 */
    public String getSeasonName() {
        return seasonName;
    }
    public String getSeasonDesc() {
        return seasonDesc;
    }

    /** toString()方法 */
    @Override
    public String toString() {
        return "Season{" +
                "seasonName='" + seasonName + '\'' +
                ", seasonDesc='" + seasonDesc + '\'' +
                '}';
    }
}
  • JDK5 之前, 的枚举类需要通过改方法进行自定义~

Java中被 Final修饰的变量的几种赋值方式

  • Final 表示"最后的、最终的"含义,变量一旦赋值后,不能被重新赋值
  • 被 Final 修饰的实例变量必须显式指定初始值
  • Final 修饰符通常和 static 修饰符一起使用来创建类常量

非静态Final赋值有三种:定义初始化、非静态代码块、构造方法

/*定义初始化时进行赋值
    在声明对象时直接赋值,赋值后就不可变了,这种是最容易想到的
*/
public class FinalTest {
    private final Integer num = 10;
}

/*代码块中赋值
    这种是在定义之初不进行赋值操作,而是在代码块中进行赋值,也是可以的
    构造块会在创建对象时被调用,每次创建时都会被调用,优先于类构造函数执行.
*/
public class FinalTest {
    private final Integer num;

    {
        num = 10;
    }
}

/*
构造器中赋值
    在创建对象时进行赋值,一旦对象创建完成,就不可变了,所以在创建完对象后set()方法是不能进行赋值的
*/
public class FinalTest {
    private final Integer num;
    
    public FinalTest(Integer num) {
        this.num = num;
    }
}

静态使用Final: static final

  • static final赋值有两种: 定义初始化、静态代码块
/* 定义初始化 */
public class FinalTest {
    private static final Integer num = 10 ;
}

/* 静态代码块
    用static{}包裹起来的代码片段,只会执行一次 静态代码块优先于构造块执行.
*/
public class FinalTest {
    private static final Integer num;
    static {
        num = 10;
    }
}

enum 关键字实现枚举类:

  • enum 定义的枚举类默认继承了 Java.lang.Enum类: 因此不能再 extends 继承其他类 但可以 implements
  • 枚举类的构造器只能使用 private 权限修饰符
  • 必须在枚举类的第一行声明枚举类对象

JDK 1.5 中可以在 switch 表达式中使用Enum定义的枚举类的对象 作为表达式

case 子句可以直接使用枚举值的名字(无需添加枚举类作为限定)

SeasonTest2.Java

**`Season.Java`**
package com.wsm.two;

import javax.sound.midi.Soundbank;

/***
 * JDK1.5 新增enum
 */
public class SeasonTest2 {
    public static void main(String[] args) {
        /** 秋天 */
        Season AUTUMN = Season.AUTUMN;
        System.out.println(AUTUMN);         //尝试注释 toString()方法输出: AUTUMN (对象名)
        //enum extends Java.lang.enum类

        /** enum常用方法 */
        //values()方法:
        //  返回枚举类型的对象数组。该方法可以很方便地遍历所有的枚举值
        //valueOf(String str)
        //  可以把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。如不是,会有运行时异常:IllegalArgumentException。
        //toString()            返回当前枚举类对象常量的名称
        /** values() */
        System.out.println("enum常用方法values()");
        Season[] values = Season.values();              //返回该enum 的所有对象
        //遍历结果集
        for (Season value : values) {
            System.out.println(value);
        }

        /** valueOf(String str) */
        System.out.println("enum常用方法valueOf(String str)");
        Season winter = Season.valueOf("WINTER");       //根据固定对象名,返回对应的enum
        System.out.println(winter);

        /** switch用法
         *      判断对象属于那一个...
         * */
        System.out.println("enum switch用法");
        switch (winter){
            case SPRING:
                System.out.println("春");
             break;
            case SUMMER:
                System.out.println("夏");
                break;
            case AUTUMN:
                System.out.println("秋");
                break;
            case WINTER:
                System.out.println("冬");
                break;
            default:
                System.out.println("没有匹配!");
        }
        
    }
}

/** 可以于自定义枚举进行比较查看~ */
enum Season{
    //1.必须在枚举类的第一行声明枚举类对象
    //枚举类的所有实例必须在枚举类中显式列出(, 分隔 ; 结尾)
    //因为枚举,本机不可修改由类访问可以取消: public static final 类
//    public static final Season SPRING = new Season("春天","春暖花开");
    SPRING("春天","春暖花开"),
    SUMMER("夏天","夏日炎炎"),
    AUTUMN("秋天","秋高气爽"),
    WINTER("冬天","冰天雪地");

    //2.声明Season对象的属性:private final修饰
    private final String seasonName;
    private final String seasonDesc;

    //3.私有化类的构造器,并给对象属性赋值
    private Season(String seasonName,String seasonDesc){
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    //扩展方法
    /** get */
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }

    /** toString
     *      注释方法直接输出发现,即使不重新toString(); 也不是打印对象的: 地址值(栈指向堆的地址!)
     *      因为: enum类,是继承于 Java.lang.enum的,而不是 Object类
     * */
//    @Override
//    public String toString() {
//        return "Season{" +
//                "seasonName='" + seasonName + '\'' +
//                ", seasonDesc='" + seasonDesc + '\'' +
//                '}';
//    }
}

enum 常用方法

方法名称 描述
values() 以数组形式返回枚举类型的所有成员
valueOf( String ) 将普通字符串转换为枚举实例
compareTo() 比较两个枚举成员在定义时的顺序
ordinal() 获取枚举成员的索引位置

enum 高级:implements实现类

  • enum 类继承了 java.lang.enum类 Java单根性所以不能在继承, 但Java 可以 多实现

  • eunm 类 还可以 实现接口...达到扩展的方式

实现方式:

  • 正常实现,重写方法.... 但这样所有的对象, 方法实现都一样!

    SeasonTest3

    Season

    Info

    public class SeasonTest3 {
        public static void main(String[] args) {
            Season autumn = Season.AUTUMN;
            autumn.show();
        }
    }
    
    //使用enum关键字枚举类 implements 实现接口,重写show()方法~
    enum Season implements Info{
        SPRING("春天","春暖花开"),
        SUMMER("夏天","夏日炎炎"),
        AUTUMN("秋天","秋高气爽"),
        WINTER("冬天","冰天雪地");
    
        //2.声明Season对象的属性:private final修饰
        private final String seasonName;
        private final String seasonDesc;
    
        //3.私有化类的构造器,并给对象属性赋值
    
        private Season(String seasonName,String seasonDesc){
            this.seasonName = seasonName;
            this.seasonDesc = seasonDesc;
        }
      //重写接口的方法!
        @Override
        public void show() {
            System.out.println("这是一个季节~");
        }
    }
    
    /** 接口 */
    interface Info{
        void show();
    }
    
  • 给每个enum 对象,来一个特有的固定实现!

    public class SeasonTest4 {
        public static void main(String[] args) {
            Season autumn = Season.AUTUMN;
            autumn.show();
        }
    }
    
    //使用enum关键字枚举类 implements 实现接口,重写show()方法~
    enum Season implements Info {
        SPRING("春天","春暖花开"){
            @Override
            public void show() { System.out.println("春天在哪里?");  }
        },
        SUMMER("夏天","夏日炎炎"){
            @Override
            public void show() { System.out.println("宁夏");           }
        },
        AUTUMN("秋天","秋高气爽"){
            @Override
            public void show() { System.out.println("秋天不回来");    }
        },
        WINTER("冬天","冰天雪地"){
            @Override
            public void show() { System.out.println("大约在冬季");  }
        };
    
        //2.声明Season对象的属性:private final修饰
        private final String seasonName;
        private final String seasonDesc;
    
        //3.私有化类的构造器,并给对象属性赋值
        private Season(String seasonName,String seasonDesc){
            this.seasonName = seasonName;
            this.seasonDesc = seasonDesc;
        }
    }
    
    /** 接口 */
    interface Info{
        void show();
    }
    

枚举集合

在 Java 语言中和枚举类相关的,还有两个枚举集合类 java.util.EnumSetjava.util.EnumMap

使用 EnumSet 可以保证元素不重复,并且能获取指定范围内的元素

public class EnumTest {
    public static void main(String[] args) {
        List<ErrorCodeEnum> list = new ArrayList<ErrorCodeEnum>();
        list.add(ErrorCodeEnum.SUCCESS);
        list.add(ErrorCodeEnum.SUCCESS);    //重复元素
        list.add(ErrorCodeEnum.SYS_ERROR);
        list.add(ErrorCodeEnum.NAMESPACE_NOT_FOUND);
        // 去掉重复数据
        EnumSet<ErrorCodeEnum> enumSet = EnumSet.copyOf(list);
        System.out.println("去重:" + enumSet);

        // 获取指定范围的枚举(获取所有的失败状态)
        EnumSet<ErrorCodeEnum> errorCodeEnums = EnumSet.range(ErrorCodeEnum.ERROR, ErrorCodeEnum.UNKNOWN_ERROR);
        System.out.println("所有失败状态:" + errorCodeEnums);
    }
}

enum ErrorCodeEnum {
    SUCCESS(1000, "success"),
    ERROR(2001, "parameter error"),
    SYS_ERROR(2002, "system error"),
    NAMESPACE_NOT_FOUND(2003, "namespace not found"),
    NODE_NOT_EXIST(3002, "node not exist"),
    NODE_ALREADY_EXIST(3003, "node already exist"),
    UNKNOWN_ERROR(9999, "unknown error");

    private int code;
    private String msg;

    ErrorCodeEnum(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int code() {   return code;  }

    public String msg() { return msg;   }
}
  • EnumMapHashMap 类似,不过它是一个专门为枚举设计的 Map 集合

  • 相比 HashMap 来说它的性能更高,因为它内部放弃使用链表和红黑树的结构,采用数组作为数据存储的结构

    • 以枚举作为 key,查询直接找到对应的 数组下标 快速定位元素

      EnumMap<枚举对象,Object>
      

为什么使用枚举?😕

更强的 类型约束

  • 在枚举没有诞生之前,也就是 JDK 1.5 版本之前

  • 我们通常会使用 int 常量来表示枚举,用来区分,状态类型: B站上传视频为例,视频一般有三个状态:草稿审核发布

    int类型本身并不具备安全性,假如某个程序员在定义int时少些了一个final关键字,

    那么就会存在被其他人修改的风险,反观枚举类,它“天然”就是一个常量类,不存在被修改的风险。

    使用 int 类型的语义不够明确 枚举更加清晰表示一种状态

单例模式:

  • 使用枚举实现 单例模式更加简单!

线程安全:

  • 枚举类最终会被编译为被 final 修饰的普通类
  • 它的所有属性也都会被 staticfinal 关键字修饰,所以枚举类在项目启动时就会被 JVM 加载并初始化 且不允许更改!线程安全

方便比较:

  • 枚举比较时使用 == 就够了,因为枚举类是在程序加载时就创建了(它并不是 new 出来的) 每个对象全局只有一个!
  • == 比较地址,相同对象的地址也相同!

ok, 枚举就介绍到这儿了,晚安,集美门😘

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容