• 【javaSE】 枚举与枚举的使用


    🎄枚举的背景及定义

    枚举是在JDK1.5以后引入的。主要用途是:将一组常量组织起来,在这之前表示一组常量通常使用定义常量的方式:

    public static final int RED = 1;
    public static final int GREEN = 2;
    public static final int BLACK = 3;
    
    • 1
    • 2
    • 3

    但是常量举例有不好的地方,例如:可能碰巧有个数字1,但是他有可能误会为是RED,现在我们可以直接用枚举来进行组织,这样一来,就拥有了类型,枚举类型。而不是普通的整形1

    public enum TestEnum {
    	RED,BLACK,GREEN;
    }
    
    • 1
    • 2
    • 3

    ⚾枚举特性总结:

    • 优点:将常量组织起来统一进行管理

    • 场景:错误状态码,消息类型,颜色的划分,状态机等等…

    • 本质:是 java.lang.Enum 的子类,也就是说,自己写的枚举类,就算没有显示的继承 Enum ,但是其默认继承了这个类

    🌲枚举的使用

    🚩switch语句

    public enum TestEnum {
        RED,BLACK,GREEN,WHITE;
        public static void main(String[] args) {
            TestEnum testEnum2 = TestEnum.BLACK;
            switch (testEnum2) {
                case RED:
                    System.out.println("red");
                    break;
                case BLACK:
                    System.out.println("black");
                    break;
                case WHITE:
                    System.out.println("WHITE");
                    break;
                case GREEN:
                    System.out.println("black");
                    break;
                default:
                    break;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    🚩常用方法

    Enum 类的常用方法
    在这里插入图片描述

    📌示例一

            /**
            * Created with IntelliJ IDEA.
            * Description:
            * User: GAOBO
            * Date: 2020-02-06
            * Time: 16:19
            */
    public enum TestEnum {
        RED, BLACK, GREEN, WHITE;
    
        public static void main(String[] args) {
            TestEnum[] testEnum2 = TestEnum.values();
            for (int i = 0; i < testEnum2.length; i++) {
                System.out.println(testEnum2[i] + " " + testEnum2[i].ordinal());
            }
            System.out.println("=========================");
            System.out.println(TestEnum.valueOf("GREEN"));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    📌示例二

            /**
            * Created with IntelliJ IDEA.
            * Description:
            * User: GAOBO
            * Date: 2020-02-06
            * Time: 16:19
            */
    public enum TestEnum {
        RED,BLACK,GREEN,WHITE;
        public static void main(String[] args) {
    //拿到枚举实例BLACK
            TestEnum testEnum = TestEnum.BLACK;
    //拿到枚举实例RED
            TestEnum testEnum21 = TestEnum.RED;
            System.out.println(testEnum.compareTo(testEnum21));
            System.out.println(BLACK.compareTo(RED));
            System.out.println(RED.compareTo(BLACK));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    刚刚说过,在Java当中枚举实际上就是一个类。所以我们在定义枚举的时候,还可以这样定义和使用枚举:

            /**
            * Created with IntelliJ IDEA.
            * Description:
            * User: GAOBO
            * Date: 2020-02-06
            * Time: 16:19
            */
    public enum TestEnum {
        RED("red",1),BLACK("black",2),WHITE("white",3),GREEN("green",4);
        private String name;
        private int key;
        /**
         * 1、当枚举对象有参数后,需要提供相应的构造函数
         * 2、枚举的构造函数默认是私有的 这个一定要记住
         * @param name
         * @param key
         */
        private TestEnum (String name,int key) {
            this.name = name;
            this.key = key;
        }
        public static TestEnum getEnumKey (int key) {
            for (TestEnum t: TestEnum.values()) {
                if(t.key == key) {
                    return t;
                }
            } 
            return null;
        }
        public static void main(String[] args) {
            System.out.println(getEnumKey(2));
        }
    }
    
    • 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
    • 32
    • 33

    注意:枚举的构造方法默认是私有的

    🎍枚举优点缺点

    优点:

    1. 枚举常量更简单安全 。

    2. 枚举具有内置方法 ,代码更优雅

    缺点:

    1. 不可继承,无法扩展

    🌴枚举和反射

    🚩枚举是否可以通过反射,拿到实例对象呢?

    博主在反射里讲过了,任何一个类,哪怕其构造方法是私有的,我们也可以通过反射拿到他的实例对象,

    那么枚举的构造方法也是私有的,我们是否可以拿到呢?

    接下来,我们来实验一下:

    同样利用上述提供的枚举类来进行举例:

    import java.lang.reflect.Constructor;
    
    /**
            * Created with IntelliJ IDEA.
            * Description:
            * User: GAOBO
            * Date: 2020-02-24
            * Time: 16:13
            */
    public enum TestEnum {
        RED("red",1),BLACK("black",2),WHITE("white",3),GREEN("green",4);
        private String name;
        private int key;
    /**
     * 1、当枚举对象有参数后,需要提供相应的构造函数
     * 2、枚举的构造函数默认是私有的 这个一定要记住
     * @param name
     * @param key
     */
    private TestEnum (String name,int key) {
        this.name = name;
        this.key = key;
    }
        public static TestEnum getEnumKey (int key) {
            for (TestEnum t: TestEnum.values()) {
                if(t.key == key) {
                    return t;
                }
            }
            return null;
        }
        public static void reflectPrivateConstructor() {
            try {
                Class<?> classStudent = Class.forName("TestEnum");
    //注意传入对应的参数,获得对应的构造方法来构造对象,当前枚举类是提供了两个参数分别是String和int。
                Constructor<?> declaredConstructorStudent = classStudent.getDeclaredConstructor(String.class,int.class);
    //设置为true后可修改访问权限
                declaredConstructorStudent.setAccessible(true);
                Object objectStudent = declaredConstructorStudent.newInstance("绿色",666);
                TestEnum testEnum = (TestEnum) objectStudent;
                System.out.println("获得枚举的私有构造函数:"+testEnum);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        public static void main(String[] args) {
            reflectPrivateConstructor();
        }
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    输出结果为:
    在这里插入图片描述
    我们看到异常信息是:
    java.lang.NoSuchMethodException: TestEnum.(java.lang.String, int)
    什么意思是? 就是没有对应的构造方法

    可是我们提供的枚举的构造方法就是两个参数分别是 String 和 int
    那么问题出现在哪里呢?还记不记得我们说过的,我们所有的枚举类,都是默认继承与 java.lang.Enum

    说到继承,继承了什么?继承了父类除构造函数外的所有东西,并且子类要帮助父类进行构造!而我们写的类,并没有帮助父类构造!

    那意思是,我们要在自己的枚举类里面,提供super吗?不是的,枚举比较特殊,虽然我们写的是两个,但是默认他还添加了两个参数,哪两个参数呢?我们看一下Enum类的源码:

    protected Enum(String name, int ordinal) {
    	this.name = name;
    	this.ordinal = ordinal;
    }
    
    • 1
    • 2
    • 3
    • 4

    也就是说,我们自己的构造函数有两个参数一个是String一个是int,同时他默认后边还会给两个参数,一个是String一个是int。也就是说,这里我们正确给的是4个参数:

        public static void reflectPrivateConstructor() {
            try {
                Class<?> classStudent = Class.forName("TestEnum");
    //注意传入对应的参数,获得对应的构造方法来构造对象,当前枚举类是提供了两个参数分别是String和int。
                Constructor<?> declaredConstructorStudent =
                        classStudent.getDeclaredConstructor(String.class,int.class,String.class,int.class);
    //设置为true后可修改访问权限
                declaredConstructorStudent.setAccessible(true);
    //后两个为子类参数,大家可以将当前枚举类的key类型改为double验证
                Object objectStudent = declaredConstructorStudent.newInstance("父类参数",666,"子类参数",888);
                TestEnum testEnum = (TestEnum) objectStudent;
                System.out.println("获得枚举的私有构造函数:"+testEnum);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    此时运行程序结果是:

    java.lang.IllegalArgumentException: Cannot reflectively create enum objects
    at java.lang.reflect.Constructor.newInstance(Constructor.java:416)
    at TestEnum.reflectPrivateConstructor(TestEnum.java:46)
    at TestEnum.main(TestEnum.java:55)

    嗯!没错,他还报错了,不过这次就是我想要的结果!此时的异常信息显示,是我的一个方法这个方法是:newInstance() 报错了!

    没错,问题就是这里,我们来看一下这个方法的源码,为什么会抛出
    java.lang.IllegalArgumentException: 异常呢?

    接下来我们再看一下newInstance() 的源码

    在这里插入图片描述
    这里我们会发现:

    枚举在这里被过滤了,你不能通过反射获取枚举类的实例

    🍀枚举总结

    • 枚举本身就是一个类,其构造方法默认为私有的,且都是默认继承与 java.lang.Enum

    • 枚举可以避免反射和序列化问题

    ⭕总结

    关于《【javaSE】 枚举与枚举的使用》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

  • 相关阅读:
    C 如何将输出的地址转化为十进制数
    HTTP协议和web服务器(Tomcat)
    杭州市IT行业人才需求地图信息系统的设计与实现
    Deepin安装英特尔AX200 Wifi驱动
    uniapp 使用地图
    面试突击44:volatile 有什么用?
    教资-中学《综合素质》(考前必背大题)
    学生党和SLAMer都可用的工具网站推荐
    现代密码学第四版杨波著-期末复习汇总
    Mybatis(第三篇:不同的返回值类型:Map和JavaBean)
  • 原文地址:https://blog.csdn.net/m0_71731682/article/details/132864657