学习JavaEE的日子 Day21 枚举

Day21

1.枚举的引入

需求:编写季节类(Season),该类只有四个对象(spring,summer,autumn,winter)

概念:枚举(enum)全称为 enumeration, 是 JDK 1.5 中引入的新特性。

public enum Color{//默认添加 public static finalRED,GREEN,BLUE;
} 

本质:尽管枚举看起来像是一种新的数据类型,实际上,枚举就是一种受限制的类,并且具有自己的方法。创建自己的enum类时,这个类继承自 java.lang.Enum。


public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable{...
}

特点

  • 枚举就是一个受限制的类,默认继承Enum
  • 枚举的第一行必须定义该枚举类型的对象
  • 枚举类型对象默认添加: public static final 类型
  • 枚举没有继承明确类(自定义枚举类默认继承Enum,Enum默认继承Object)
  • 枚举类不能被继承
  • 枚举里可以有构造方法、成员方法、静态方法、抽象方法
  • 枚举可以实现接口
  • 枚举里没有定义方法,可以在最后一个对象后面加逗号、分号或什么都不加

优势

  • 增强代码可读性

  • 枚举型可直接与数据库交互

  • switch语句优势

  • 编译优势

(枚举类编译时,没有把常量值编译到代码中,即使常量值发生改变,也不会影响引用常量的类 )

  • 将常量组织起来,统一管理

  • 去除equals两者判断 由于常量值地址唯一,使用枚举可以直接通过“==”进行两个值之间的对比,性能会有所提高

经验:一个类有固定几个对象,就用枚举代替

常规写法:

public class Test01 {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);System.out.println(summer);System.out.println(autumn);System.out.println(winter);}
}
public class Season {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("冬天", "银装素裹");private String name;private String info;private Season() {}private Season(String name, String info) {this.name = name;this.info = info;}// get,set,toString省略
}

枚举写法:

注意:使用枚举来解决该需求

经验:一个类有固定几个对象,就用枚举代替

public class Test01 {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);System.out.println(summer);System.out.println(autumn);System.out.println(winter);}
}
//注意:枚举就是一个特殊的类,但是他也是引用数据类型的一种
//注意:枚举没有显示继承
//注意:枚举有隐式继承 -> Season extends Enum extends Object
public enum Season{//注意:枚举类第一行必须声明对象//注意:枚举对象默认使用public static final修饰 -- public static final Season spring = new Season("春天","春雨绵绵");spring("春天","春雨绵绵"),summer("夏天","烈日炎炎"),autumn("秋天","硕果累累"),winter("冬天","白雪皑皑");private String name;private String info;//注意:枚举类的构造方法都是私有的private Season() {}private Season(String name, String info) {this.name = name;this.info = info;}//get,set,toString省略
}

2.枚举的常用方法

方法名解释
Enum.valueOf(Class enumType, String name)根据字符串找到该枚举类中的对象
public static void values()获取该枚举类对象数组
public static void valueOf(String args0)根据字符串获取该枚举类中的对象
public class Test02 {public static void main(String[] args) {//通过字符串获取枚举类中的对象Season season1 = Enum.valueOf(Season.class, "spring");System.out.println(season1);//通过字符串获取枚举类中的对象Season season2 = Season.valueOf("spring");System.out.println(season2);//获取Season枚举类中所有的对象,返回数组Season[] values = Season.values();for (Season season : values) {System.out.println(season);}}
}

3.手撕枚举底层源码

public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {private final String name;//枚举对象名private final int ordinal;//枚举编号(从0开始)protected Enum(String name, int ordinal) {this.name = name;this.ordinal = ordinal;}}
//枚举本质意义上就是一个类,默认继承Enum
public final class Season extends Enum{public static final Season spring;public static final Season summer;public static final Season autumn;public static final Season winter;private String name;private String info;//存放该枚举类的所有对象 -- 数组private static final Season[] ENUM$VALUES;//静态代码块(初始化枚举对象、将枚举对象存入ENUM$VALUES数组中)static{spring = new Season("spring", 0, "春天", "春雨绵绵");summer = new Season("summer", 1, "夏天", "烈日炎炎");autumn = new Season("autumn", 2, "秋天", "硕果累累");winter = new Season("winter", 3, "冬天", "白雪皑皑");ENUM$VALUES = (new Season[] {spring, summer, autumn, winter});}//改造了我们写的无参构造 -- private Season(){}private Season(String s, int i){super(s, i);}//改造了我们写的有参构造 -- private Season(String name,String info){}private Season(String s, int i, String name, String info){super(s, i);this.name = name;this.info = info;}//get,set省略public String toString(){return (new StringBuilder(String.valueOf(name))).append(" -- ").append(info).toString();}public static Season[] values(){Season[] aseason = ENUM$VALUES;//获取ENUM$VALUESint i  = aseason.length;//i - 4//创建了一个与ENUM$VALUES长度相同的数组Season[] aseason1 = new Season[i];System.arraycopy(aseason, 0, aseason1, 0, i);return aseason1;}public static Season valueOf(String s){return (Season)Enum.valueOf(com/qf/enum02/Season, s);}}

4.面试题

4.1 研究switch如何判断枚举类型

注意:底层会创建一个枚举个数的数组 – ai[1,2,3,4]

public class Test03 {public static void main(String[] args) {switch (Season.spring) {case spring:System.out.println("春天");break;case summer:System.out.println("夏天");break;case autumn:System.out.println("秋天");break;case winter:System.out.println("冬天");break;}}
}

底层源码

public class Test03{private static int[] $SWITCH_TABLE$com$qf$enum02$Season;//[1,2,3,4]public static void main(String args[]){//[1,2,3,4]int[] ai = $SWITCH_TABLE$com$qf$enum02$Season();switch (ai[Season.spring.ordinal()]){//ai[0] -- 1case 1: // '\001'System.out.println("春天");break;case 2: // '\002'System.out.println("夏天");break;case 3: // '\003'System.out.println("秋天");break;case 4: // '\004'System.out.println("冬天");break;}}static int[] $SWITCH_TABLE$com$qf$enum02$Season(){//[0,0,0,0]int[] ai = new int[Season.values().length];//Season.values().length - 4try{//Season.autumn.ordinal() -- 2ai[Season.autumn.ordinal()] = 3;//ai[2] = 3;}catch (NoSuchFieldError ) { }try{//Season.spring.ordinal() - 0ai[Season.spring.ordinal()] = 1;//ai[0] = 1}catch (NoSuchFieldError ) { }try{//Season.summer.ordinal - 1ai[Season.summer.ordinal()] = 2;//ai[1] = 2}catch (NoSuchFieldError ) { }try{//Season.winter.ordinal() - 3ai[Season.winter.ordinal()] = 4;//ai[3] = 4}catch (NoSuchFieldError ) { }//ai -> [1,2,3,4]return $SWITCH_TABLE$com$qf$enum02$Season = ai;}
}

4.2 研究switch如何判断String类型

注意:底层原理就是先判断hash值,然后再判断两个字符串是否相同(equals)

public class Test04 {public static void main(String[] args) {switch ("abc") {case "abc":System.out.println("abc");break;case "def":System.out.println("def");break;case "zyx":System.out.println("xyz");break;}}
}

底层源码

//研究String的hash值是如何算出来的
String str = "abc";public class String{final char[] value;//['a','b','c']public int hashCode() {int h = hash;if (h == 0 && value.length > 0) {char[] val = value;for (int i = 0; i < value.length; i++) {h = 31 * h + val[i];}hash = h;}return h;}}
public class Test04{public static void main(String args[]){String s;switch ((s = "abc").hashCode()){//96354case 96354://"abc".hashCode();if (s.equals("abc"))System.out.println("abc");break;case 99333: //"def".hashCode();if (s.equals("def"))System.out.println("def");break;case 121113: //"zyx".hashCode();if (s.equals("zyx"))System.out.println("xyz");break;}}
}

补:hash值一样,不需要if判断可以吗?

public class Test05 {/*** 知识点:研究switch如何判断String类型* * 注意:底层原理就是先判断hash值,然后再判断两个字符串是否相同(equals)*/public static void main(String[] args) {System.out.println("Aa".hashCode());System.out.println("BB".hashCode());switch ("Aa") {case "BB":System.out.println("BB");break;case "Aa":System.out.println("Aa");break;case "zyx":System.out.println("xyz");break;}}
}
public class Test05{public static void main(String args[]){String s;switch ((s = "Aa").hashCode()){//2112case 2112: //"BB".hashCode() -- "Aa".hashCode()if (!s.equals("BB")){if (s.equals("Aa"))System.out.println("Aa");} else{System.out.println("BB");}break;case 121113: if (s.equals("zyx"))System.out.println("xyz");break;}}
}

5.枚举案例 之 状态机

//信号灯的枚举
public enum Signal {RED,YELLOW,GREEN;
}
public class Test01 {public static void main(String[] args) {Scanner scan = new Scanner(System.in);System.out.println("请选择信号灯:RED、YELLOW、GREEN");String str = scan.next();Signal signal = Signal.valueOf(str);String trafficInstruct = getTrafficInstruct(signal);System.out.println(trafficInstruct);scan.close();}public static String getTrafficInstruct(Signal signal){String instruct = "信号灯故障";switch (signal) {case RED:instruct = "红灯停";break;case YELLOW:instruct = "黄灯请注意";break;case GREEN:instruct = "绿灯行";break;}return instruct;}
}

6.枚举案例 之 错误码/状态码

public enum AddCode {ERR_1(-1,"添加失败 - 学生信息不合法"),ERR_2(-2,"添加失败 - 有该学生"),OK(1,"添加成功");private int code;private String message;private AddCode() {}private AddCode(int code, String message) {this.code = code;this.message = message;}//get,set,toString省略
}
public class Test01 {public static void main(String[] args) {System.out.println(AddCode.ERR_1.getCode());System.out.println(AddCode.ERR_1.getMessage());System.out.println(AddCode.ERR_1);}
}

7.枚举案例 之 组织枚举

应用场景:把一些同类别的枚举使用类或接口组织起来

注意:一般使用接口去组织多个枚举

原因:

使用类去组织枚举,类里的枚举默认添加static修饰 – 静态内部类

使用接口去组织枚举,接口的枚举默认添加public static修饰 – 接口内部类(公有静态内部类)

就是说,在类中组织 enum,如果你不给它修饰为 public,那么只能在本包中进行访问。

​ 考虑到其他包中还可以使用到枚举对象,所以推荐使用接口去组织

public interface Code {enum UpdateCode {ERR_1(-1,"修改失败 -- 学生信息不合法"),ERR_2(-2,"修改失败 -- 没有该学生"),ERR_3(-3,"修改失败 -- 修改值的信息不合法"),ERR_4(-4,"修改失败 -- 目标班级上有学生"),ERR_5(-5,"修改失败 -- 目标学号上有学生"),OK(1,"修改成功");private int code;private String message;private UpdateCode() {}private UpdateCode(int code, String message){this.code = code;this.message = message;}//get,set,toString省略}}

8.枚举案例 之 策略枚举

优点:这种枚举通过枚举嵌套枚举的方式,将枚举常量分类处理。

这种做法虽然没有switch语句简洁,但是更加安全、灵活。

需求:模拟公司计算工资的功能

分析:

员工类别:行政、讲师

部门:Java(讲师)、Python(讲师)、HTML(讲师)、总经办(行政)、人力(行政)、财务(行政)

行政工资构成:基本工资 + 绩效

讲师工资构成:基本工资 + 绩效 + 课时费*课时

//public final class QianFeng extends Enum
public enum QianFeng {Java(StaffType.teacher),Python(StaffType.teacher),HTML(StaffType.teacher),GeneralManagerOffice(StaffType.admin),HR(StaffType.admin),finance(StaffType.admin);private StaffType staffType;private QianFeng(StaffType staffType) {this.staffType = staffType;}public double getSalary(double basicSalary, double performance, double classFees, double classHours){return staffType.calculateSalary(basicSalary, performance, classFees, classHours);}//员工类型//public static abstract class QianFeng$StaffType extends Enumpublic enum StaffType{//class QianFeng$StaffType$1 extends QianFeng$StaffType//QianFeng$StaffType$1 admin = QianFeng$StaffType$1(){//	@Override//	public double calculateSalary(double basicSalary, double performance, double classFees, double classHours) {//		return 0;//	}//}admin {//行政类别@Overridepublic double calculateSalary(double basicSalary, double performance, double classFees, double classHours) {BigDecimal big1 = new BigDecimal(String.valueOf(basicSalary));BigDecimal big2 = new BigDecimal(String.valueOf(performance));double salary = big1.add(big2).doubleValue();return salary;}},//class QianFeng$StaffType$2 extends QianFeng$StaffType//QianFeng$StaffType$2 teacher = QianFeng$StaffType$2(){//	@Override//	public double calculateSalary(double basicSalary, double performance, double classFees, double classHours) {//		return 0;//	}//}teacher {@Overridepublic double calculateSalary(double basicSalary, double performance, double classFees, double classHours) {BigDecimal big1 = new BigDecimal(String.valueOf(basicSalary));BigDecimal big2 = new BigDecimal(String.valueOf(performance));BigDecimal big3 = new BigDecimal(String.valueOf(classFees));BigDecimal big4 = new BigDecimal(String.valueOf(classHours));double salary = big3.multiply(big4).add(big1).add(big2).doubleValue();return salary;}};public abstract double calculateSalary(double basicSalary, double performance, double classFees, double classHours);}
}
public class Test01 {public static void main(String[] args) {double salary1 = QianFeng.Java.getSalary(1800, 200, 88, 9);System.out.println(salary1);double salary2 = QianFeng.GeneralManagerOffice.getSalary(50000, 30000, 0, 0);System.out.println(salary2);}
}

总结

1.枚举特点,优势

2.枚举的常用方法

3.底层原理

4.面试题

5.枚举案例
状态机
错误码
组织枚举
策略枚举 — 难点

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

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

相关文章

基带信号处理设计原理图:2-基于6U VPX的双TMS320C6678+Xilinx FPGA K7 XC7K420T的图像信号处理板

基于6U VPX的双TMS320C6678Xilinx FPGA K7 XC7K420T的图像信号处理板 综合图像处理硬件平台包括图像信号处理板2块&#xff0c;视频处理板1块&#xff0c;主控板1块&#xff0c;电源板1块&#xff0c;VPX背板1块。 一、板卡概述 图像信号处理板包括2片TI 多核DSP处理…

Linux进程管理:(二)进程调度原语

文章说明&#xff1a; Linux内核版本&#xff1a;5.0 架构&#xff1a;ARM64 参考资料及图片来源&#xff1a;《奔跑吧Linux内核》 Linux 5.0内核源码注释仓库地址&#xff1a; zhangzihengya/LinuxSourceCode_v5.0_study (github.com) 进程调度的概念比较简单&#xff0c…

Java学习笔记NO.17

T1&#xff1a;合并两个排序好的整数数组 import java.util.Arrays;public class MergeSortedArrays {public static int[] mergeArrays(int[] arr1, int[] arr2) {int[] result new int[arr1.length arr2.length];int i 0, j 0, k 0;while (i < arr1.length &&am…

一个简单的iOS天气应用程序源码

创建一个简单的iOS天气应用程序涉及到多个步骤&#xff0c;包括设置项目、编写代码和使用外部API。由于篇幅限制&#xff0c;我将提供一个基础的示例&#xff0c;这个例子会展示如何创建一个简单的UI&#xff0c;获取用户的当前位置&#xff0c;并从OpenWeatherMap API获取天气…

QPS 提升 10 倍!滴滴借助 StarRocks 物化视图实现低成本精确去重

作者&#xff1a;滴滴 OLAP 开发工程师 刘雨飞 小编导读&#xff1a; 滴滴于 2022 年引入了 StarRocks。经过一年多的努力&#xff0c;StarRocks 逐渐替代了原有技术栈&#xff0c;成为滴滴内部主要的 OLAP 引擎。截至 2023 年 12 月&#xff0c;滴滴已经成功建立了超过 40 个 …

Cesium插件系列——3dtiles压平

本系列为自己基于cesium写的一套插件具体实现。 这里是根据Cesium提供的CustomShader来实现的。 在CustomShader的vertexShaderText里&#xff0c;需要定义vertexMain函数&#xff0c;例如下&#xff1a; struct VertexInput {Attributes attributes;FeatureIds featureIds;…

LVGL常用部件使用总结之图片部件

图片部件可用于显示图片&#xff0c;图片源可以是 C 语言数组格式的文件、二进制的.bin 文件以及图标字体。值得注意的是&#xff0c;图片部件要显示 BMP、JPEG 等格式的图片&#xff0c;则必须经过解码。 图片部件的组成部分仅有一个&#xff1a;主体&#xff08;LV_PART_MAIN…

URI到底是个啥

URI是统一资源标识符&#xff08;Uniform Resource Identifier&#xff09;&#xff0c;URL是统一资源定位符&#xff08;Uniform Resource Locator&#xff09;。 具体如何标记和区分服务器上的资源用的其实就是URI&#xff0c;因为其经常出现在浏览器的地址栏里&#xff0c;…

Verilog(未完待续)

Verilog教程 这个教程写的很好&#xff0c;可以多看看。本篇还没整理完。 一、Verilog简介 什么是FPGA&#xff1f;一种可通过编程来修改其逻辑功能的数字集成电路&#xff08;芯片&#xff09; 与单片机的区别&#xff1f;对单片机编程并不改变其地电路的内部结构&#xff0…

Parallel Computing - 一文讲懂并行计算

目录 Throughput/LatencySerial ComputingParallel ComputingTypes of parallel computersSimple 4-width SIMDAmdahls lawTypes of parallelism**Data Parallel Model**Task parallel PartitioningDomain DecompositionFunctional Decomposition CommunicationsExample that d…

java调用chatgpt接口,实现专属于自己的人工智能助手

文章目录 前言导包基本说明请求参数响应参数创建请求和响应的VO类 代码编写使用最后说明 前言 今天突然突发奇想&#xff0c;就想要用java来调用chatget的接口&#xff0c;实现自己的聊天机器人&#xff0c;但是网上找文章&#xff0c;属实是少的可怜(可能是不让发吧)。找到了…

ESP32 web 对接华为云平台--MQTT协议

文章目录 前言一、MQTT协议二、如何使用MQTT协议对接华为云1.注册华为云账号2.设备接入中创建资源空间3.如何连接4.通过MQTT.fx工具做初步对接4.1 设置连接信息4.2 连接平台 5.查看平台设备信息 三. 设备测对接平台1.ESP测引入MQTT库2.编码2.1前端编码修改2.2 后端接口修改 3.M…

element-plus+vue3表单含图片(可预览)(线上图片)

一、要实现的效果&#xff1a; 二、如果期间出现这样的效果&#xff08;表格穿透过来了&#xff09;&#xff0c;加上了这行代码就可以了&#xff1a; preview-teleported“true” 如果仅测试用&#xff0c;建议使用线上图片链接的形式&#xff0c;免得本地地址不生效&#xf…

SSH 的两种认证方式

SSH&#xff08;Secure Shell&#xff09;提供了几种不同的认证方式&#xff0c;其中两种最常见的方式是密码认证和密钥认证。以下是它们的详细介绍&#xff1a; 密码认证&#xff1a; 原理&#xff1a;用户在连接时输入用户名和密码&#xff0c;然后将密码传输到远程服务器进行…

数学实验-Matlab使用(1)

使用方法以及笔记均在文件中 class1_func1.m function f class1_func1(x) % f为输出&#xff0c;输出有多个时需要用中括号以矩阵的方式包起来 % x为输入f sin(x)class1_func2.m function [a,b,u,v] class1_func2(x,y)[a,b] eig(x)[u,v] eig(y)class1.m % 当语句后有…

yolov9从头开始训练

yolov9从头开始训练 一、准备数据集 数据集相关文件存放布局如下 yolov9-datasets ├── train │ ├── images │ │ ├── image.jpg │ │ ├── │ └── labels │ ├── image.txt │ ├── ├── valid │ ├── images │ │ ├── image.jpg │ │ ├─…

吴恩达deeplearning.ai:模型选择交叉验证测试集的训练方法

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai专栏 在上一节中&#xff0c;我们了解了如何利用测试集来评估模型性能。今天我们来进一步完善这个想法&#xff0c;让你使用该技术自动选择一个更好的模型。 文章目录 模型选择交叉验证 Cross Va…

SpringBoot 框架(上)

SpringBoot SpringBoot概述依赖管理自动配置SpringBoot 注解使用ConfigurationImport(value {Cat.class,Dog.class})ImportResource(locations "classpath:beans.xml") yaml 标记语言概述基本语法数据类型字面量对象数组 使用细节 Rest 风格请求处理概述注意事项 接…

vue2 开发记录

el-select 如何修改选择项的样式/el-select-dropdown__item 文字上下显示 测试代码 <div stylemargin-left: 100px><!-- 测试代码--><el-select filterablesizemini><div classxxx-el-select><el-optionv-foritem in [{key:1,des:2,…

AVT Prosilica GC Vision Cameras 相机视觉说明使用安装。具体详情内容可参看PDF目录内容。

AVT Prosilica GC Vision Cameras 相机视觉说明使用安装。具体详情内容可参看PDF目录内容。