教你精通Java语法之第十四章、枚举

news2024/11/13 11:20:25

目录

一、背景及定义

二、使用

2.1switch语句

2.2常用方法

三、枚举优点缺点

四、枚举和反射

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

五、总结

六、面试问题


一、背景及定义

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

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

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

public class Constant {
    public static  final int RED = 1;
    public static  final int GREEN = 2;
    public static  final int BLACK = 3;
}

优点:将常量组织起来统一进行管理
场景:错误状态码,消息类型,颜色的划分,状态机等等....

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


二、使用

2.1switch语句

/**
 * @Author 12629
 * @Description:枚举类 也会独立生成一个 字节码文件
 *
 *  RED  BLACK  都是枚举对象
 */
public enum TestEnum {
    RED(0.1,"红色"),BLACK(1.1,"黑色"),
    GREEN(2.1,"绿色"),WHITE(3.1,"白色");

    public String color;
    public double ordinal;

    /**
     * 枚举的构造方法 默认是私有的
     * @param ordinal
     * @param color
     */
    private TestEnum(double ordinal,String color) {
        this.ordinal = ordinal;
        this.color = color;
    }

    @Override
    public String toString() {
        return "TestEnum{" +
                "color='" + color + '\'' +
                ", ordinal=" + ordinal +
                '}';
    }
    public static void main(String[] args) {
        TestEnum testEnum = TestEnum.BLACK;
        switch (testEnum) {
            case RED:
                System.out.println("RED");
                break;
            case BLACK:
                System.out.println("BLACK");
                break;
            case GREEN:
                System.out.println("GREEN");
                break;
            default:
                System.out.println("颜色错误");
                break;
        }
    }


}

2.2常用方法

Enum 类的常用方法

public enum TestEnum {
    RED(0.1,"红色"),BLACK(1.1,"黑色"),
    GREEN(2.1,"绿色"),WHITE(3.1,"白色");

    public String color;
    public double ordinal;

    /**
     * 枚举的构造方法 默认是私有的
     * @param ordinal
     * @param color
     */
    private TestEnum(double ordinal,String color) {
        this.ordinal = ordinal;
        this.color = color;
    }

    @Override
    public String toString() {
        return "TestEnum{" +
                "color='" + color + '\'' +
                ", ordinal=" + ordinal +
                '}';
    }

    public static void main(String[] args) {
        TestEnum[] testEnums = TestEnum.values();

        for (int i = 0; i < testEnums.length; i++) {
            System.out.print(testEnums[i]+" "+testEnums[i].ordinal()+" ");
        }
        System.out.println();

        TestEnum testEnum1 = TestEnum.valueOf("WHITE");
        System.out.println(testEnum1);

        System.out.println(BLACK.compareTo(GREEN));
    }
}

重要:枚举的构造方法默认是私有的

(通过反射进行验证)

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * @Author 12629
 * @Description:
 */
public class Test {


    public static void reflectPrivateConstructor() {
        try {
            Class<?> c1 = Class.forName("demo1enum.TestEnum");
            Constructor<?> constructor =
                    c1.getDeclaredConstructor(String.class,int.class,
                            double.class,String.class);

            constructor.setAccessible(true);

            TestEnum testEnum =
                    (TestEnum)constructor.newInstance("123",8,9.9,"青色");

            System.out.println(testEnum);

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }




    public static void main(String[] args) {
        reflectPrivateConstructor();

    }
}

三、枚举优点缺点

优点:
1. 枚举常量更简单安全 。
2. 枚举具有内置方法 ,代码更优雅
缺点:
1. 不可继承,无法扩展


四、枚举和反射

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

我们刚刚在反射里边看到了,任何一个类,哪怕其构造方法是私有的,我们也可以通过反射拿到他的实例对象,那么枚举的构造方法也是私有的,我们是否可以拿到呢?接下来,我们来实验一下:
同样利用上述提供的枚举类来进行举例:

public class Test {


    public static void reflectPrivateConstructor() {
        try {
            Class<?> c1 = Class.forName("demo1enum.TestEnum");
            Constructor<?> constructor =
                    c1.getDeclaredConstructor(String.class,int.class,
                            double.class,String.class);

            constructor.setAccessible(true);

            TestEnum testEnum =
                    (TestEnum)constructor.newInstance("123",8,9.9,"青色");

            System.out.println(testEnum);

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }




    public static void main(String[] args) {
        reflectPrivateConstructor();

    }
}

输出结果:java.lang.NoSuchMethodException: TestEnum.<init>(java.lang.String, int)
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at TestEnum.reflectPrivateConstructor

异常信息是: java.lang.NoSuchMethodException: TestEnum.<init>(java.lang.String, int) ,什么
意思是:就是没有对应的构造方法,我的天呐!我们提供的枚举的构造方法就是两个参数分别是String 和int啊!!!!问题出现在哪里呢?还记不记得我们说过的,我们所有的枚举类,都是默认继承与java.lang.Enum ,说到继承,继承了什么?继承了父类除构造函数外的所有东西,并且子类要帮助父类进行构造!而我们写的类,并没有帮助父类构造!那意思是,我们要在自己的枚举类里面,提供super吗?不是的,枚举比较特殊,虽然我们写的是两个,但是默认他还添加了两个参数,哪两个参数呢?我们看一下Enum类的源码:

protected Enum(String name, int ordinal) {
    this.name = name;
    this.ordinal = ordinal;
}

也就是说,我们自己的构造函数有两个参数一个是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();
        }
    }

此时运行程序结果是:

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: 异常呢?

是的,枚举在这里被过滤了,你不能通过反射获取枚举类的实例!这道题是2017年阿里巴巴曾经问到的一个问题,不看不知道,一看吓一跳!同学们记住这个坑。原版问题是为什么枚举实现单例模式是安全的?希望同学们记住这个问题! 


五、总结

1、枚举本身就是一个类,其构造方法默认为私有的,且都是默认继承与java.lang.Enum
2、枚举可以避免反射和序列化问题
3、枚举的优点和缺点


六、面试问题

1.写一个单例模式

public class Singleton {
    private volatile static Singleton uniqueInstance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            synchronized (Singleton.class){
                if(uniqueInstance == null){//进入区域后,再检查一次,如果仍是null,才创建实例
                    uniqueInstance = new Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

2.用静态内部类实现一个单例模式

class Singleton {
    /** 私有化构造器 */
    private Singleton() {
    }
    /** 对外提供公共的访问方法 */
    public static Singleton getInstance() {
        return UserSingletonHolder.INSTANCE;
    }
    /** 写一个静态内部类,里面实例化外部类 */
    private static class UserSingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
}
public class Main {
    public static void main(String[] args) {
        Singleton u1 = Singleton.getInstance();
        Singleton u2 = Singleton.getInstance();
        System.out.println("两个实例是否相同:"+ (u1==u2));
    }
}

3.用枚举写一个单例模式

public enum TestEnum {
    INSTANCE;
    public TestEnum getInstance(){
        return INSTANCE;
    }
    public static void main(String[] args) {
        TestEnum singleton1=TestEnum.INSTANCE;
        TestEnum singleton2=TestEnum.INSTANCE;
        System.out.println("两个实例是否相同:"+(singleton1==singleton2));
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/548122.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

触发器章节小结

触发器&#xff08;Flip Flop&#xff09; 4.1 SR锁存器&#xff08;Set-Reset Latch&#xff09; 4.1.1 或非门构成的SR锁存器 SD称为置位端或置1输入端&#xff1b; RD称为复位端或置0输入端。 当SD 1、RD 0时,Q1、Q’0。在SD 1信号消失以后&#xff08;即SD 回到0)&#…

AI绘画-Midjourney基础1-突破想象的界限:掌握文本引导的图像生成技巧

Midjourney是一款 AI 绘画工具&#xff0c;可以根据你的提示&#xff08;本文中称为 prompt&#xff09;创作出各种图像。你只需要在Discord上和一个机器人聊天&#xff0c;就可以用简单的命令来控制它。目前已不支持免费试用&#xff0c;可以选择付费计划来获得更多功能和优势…

viet构建项目及<script setup>的用法

vite构建项目 官方文档&#xff1a;https://v3.cn.vuejs.org/guide/installation.html#vite vite 官网&#xff1a;https://vitejs.cn 什么是 vite&#xff1f;—— 新一代前端构建工具。 优势如下&#xff1a; 开发环境中&#xff0c;无需打包操作&#xff0c;可快速的冷启动。…

操作系统易错题

操作系统易错题 假设某硬盘由5个盘片构成&#xff08;共有8个记录面&#xff09;&#xff0c;盘面有效记录区域的外直径为30cm&#xff0c;内直径为10cm&#xff0c;记录位密度为250位/mm&#xff0c;磁道密度为16道/mm&#xff0c;每磁道分16个扇区&#xff0c;每扇区512字节&…

【图像分割】卫星遥感影像道路分割:D-LinkNet算法解读

前言 因为毕设中的部分内容涉及到卫星遥感影像道路分割&#xff0c;因此去对相关算法做了一些调研。 本文所使用数据集为DeepGlobe&#xff0c;来自于CVPR2018年的一个挑战赛&#xff1a;DeepGlobe Road Extraction Challenge。 D-LinkNet为该挑战赛的冠军算法。 考虑到D-Lin…

时间序列预测 | Matlab基于遗传算法优化BP神经网络(GA-BP)的时间序列预测,matlab代码

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列预测 | Matlab基于遗传算法优化BP神经网络(GA-BP)的时间序列预测,matlab代码 评价指标包括:R2、MAE、MSE、RMSE等,代码质量极高,方便学习和替换数据。 部分源码 %% 清空环境变量 warning off …

Flink学习——处理函数ProcessFunction及多流转换

处理函数 在DataStream的更底层&#xff0c;我们可以不定义任何具体的算子&#xff08;如map()&#xff0c;filter()等&#xff09;二只提炼出一个统一的“处理”&#xff08;process&#xff09;操作 。它是所有转换算子的概括性的表达。可以自定义处理逻辑。 所以这一层接口就…

Springcloud1--->Eureka注册中心

目录 Eureka原理Eureka入门案例编写EurekaServer将user-service注册到Eureka消费者从Eureka获取服务 Eureka详解基础架构高可用的Eureka Server失效剔除和自我保护 Eureka原理 Eureka&#xff1a;就是服务注册中心&#xff08;可以是一个集群&#xff09;&#xff0c;对外暴露自…

开心档之MySQL 数据类型

目录 MySQL 数据类型 数值类型 日期和时间类型 字符串类型 MySQL 中定义数据字段的类型对你数据库的优化是非常重要的。 MySQL 支持多种类型&#xff0c;大致可以分为三类&#xff1a;数值、日期/时间和字符串(字符)类型。 数值类型 MySQL 支持所有标准 SQL 数值数据类型…

矢量图形处理控件CAD .NET介绍以及安装

CAD .NET一款在CAD领域被广泛应用的控件&#xff0c;可以快速准确的阅读DWG和DXF文件&#xff0c;并且通过Windows GDI方法绘制件&#xff0c;支持多种文件格式&#xff0c;包括DWG、DXF、Gerber、光栅图像等&#xff0c;并支持部分编辑功能。 CAD.NET最新下载https://www.evg…

Android 性能优化篇之SharedPreferences使用优化

简介&#xff1a; SharedPreferences(以下简称SP)是Android本地存储的一种方式&#xff0c;是以key-value的形式存储在/data/data/项目包名/shared_prefs/sp_name.xml里 SP的使用及存在的问题 SharedPreferences(以下简称SP)是Android本地存储的一种方式&#xff0c;是以key-…

机器学习吴恩达笔记第一篇——基于梯度下降的线性回归(零基础)

机器学习吴恩达笔记第一篇——基于梯度下降的线性回归&#xff08;零基础&#xff09; 一、线性回归——理论&#xff08;单变量&#xff09; 1、 假设函数h(x)为&#xff1a; ​ h ( x ) θ 0 θ 1 X h(x)\theta_0\theta_1 X h(x)θ0​θ1​X 2、要拟合数据成一条直线&…

如何让 300 万程序员爱上 CODING?

**《DNSPod十问》**是由腾讯云企业中心推出的一档深度谈话栏目&#xff0c;通过每期向嘉宾提出十个问题&#xff0c;带着广大读者站在产业互联网、科技领域精英的肩膀上&#xff0c;俯瞰各大行业发展趋势和前沿技术革新。 刘毅&#xff0c;腾讯云 CODING CEO、腾讯云开发者产品…

第十六章_Redis案例落地实战bitmap/hyperloglog/GEO

统计的类型有哪些 亿级系统中常见的四种统计 聚合统计 统计多个集合元素的聚合结果&#xff0c;就是前面讲解过的交差并等集合统计 复习命令 交并差集和聚合函数的应用 排序统计 抖音短视频最新评论留言的场景&#xff0c;请你设计一个展现列表。考察你的数据结构和设计思…

Nsudo,建议有编程基础的人使用,获取管理员和超级管理员权限

资源地址&#xff1a; https://download.csdn.net/download/yaosichengalpha/87801699 Nsudo,建议有编程基础的人使用&#xff0c;获取管理员和超级管理员权限 NSudo是一款非常不错的系统管理工具&#xff0c;他是基于raymai97的超级命令提示符&#xff0c;可以帮助我们获取T…

MybatisPlus--基础入门!真滴方便

目录 一、简介 2.特性 二、入门 1.创建springboot 项目 注意&#xff1a;引入 MyBatis-Plus 之后请不要再次引入 MyBatis 以及 MyBatis-Spring&#xff0c;以避免因版本差异导致的问题 2.数据准备 3.配置application.yml 4.代码 BaseMapper<>很重要&#xff01;…

vue 本地/PC端访问微信云数据库

1. 解决跨域访问问题 新建文件 vue.config.js // 后端服务器地址 let url "http://localhost:8888"; module.exports {publicPath: "./", // 【必要】静态文件使用相对路径outputDir: "./dist", //打包后的文件夹名字及路径devServer: {// 开…

组合数学第二讲

可以把取出来的数从小到大排序&#xff0c;第一个数不变&#xff0c;第二个数1&#xff0c;以此类推... 总共的情况为&#xff0c;数字取完后可再依次减回去&#xff0c;保证数在100以内 k-element multisets 引出下面的二项式系数 binomial coefficients&#xff08;二项式系…

线段树C++实现

一、本题线段树数组数据和结构 data[]{1,2,-3,5,6,-2,7,1,12,30,-10}&#xff0c;11个元素。 二、各个函数和结构 &#xff08;一&#xff09;线段树结构 创建线段树的结构&#xff0c; l、r为左边界和右边界&#xff0c;maxV和minV为最大值和最小值&#xff0c;sum为和&#…

English Learning - L3 作业打卡 Lesson2 Day12 2023.5.16 周二

English Learning - L3 作业打卡 Lesson2 Day12 2023.5.16 周二 引言&#x1f349;句1: Dollars are called greenbacks because that is the color of the back side of the paper money.成分划分弱读连读爆破语调 &#x1f349;句2: The color black is used often in expres…