面试题:Java Switch 是如何支持 String 的,为什么不支持 long

目录

  • 前言
  • 一、结论
  • 二、枚举类型是咋变成 int 类型的?
  • 三、String 类型是咋变成 int 类型的?
  • 四、它们的包装类型支持吗?


前言

我们知道Java Switch 支持byte、short、int类型,在JDK 1.5 时,支持了枚举类型,在 JDK1.7时,又支持了String类型。那么它为什么就不能支持long类型呢,明明它跟 byte、short、int 一样都是数值型,它又是咋支持 String 类型的呢?

一、结论

不卖关子,先说结论:

switch 底层是使用 int 型 来进行判断的,即使是枚举、String类型,最终也是转变成 int 型。由于 long 型表示范围大于
int 型,因此不支持 long 类型。

下面详细介绍下各个类型是如何被转变成 int 类型的,使用的编译命令为 javac,反编译网站为:http://javare.cn

二、枚举类型是咋变成 int 类型的?

在没有实验之前,我想当然的认为它是不是根据枚举的 int 型字段来计算的(因为一般枚举都是一个int型,一个string型),但是转念一想,万一枚举没有 int 型字段呢,万一有多个 int 型字段呢,所以肯定不是这样的,下面看实验吧。

定义两个枚举类,一个枚举类有一个int型属性,一个string型属性,另外一个枚举类只有一个string属性:

public enum SexEnum {MALE(1, "男"),FEMALE(0, "女");private int type;private String name;SexEnum(int type, String name) {this.type = type;this.name = name;}
}
public enum Sex1Enum {MALE("男"),FEMALE("女");private String name;Sex1Enum(String name) {this.name = name;}
}

然后编写一个测试类,并且让两个枚举 switch 的 FEMALE 和 MALE 对应的返回值不同:

public class SwitchTest {public int enumSwitch(SexEnum sex) {switch (sex) {case MALE:return 1;case FEMALE:return 2;default:return 3;}}
 	public int enum1Switch(Sex1Enum sex) {switch (sex) {case FEMALE:return 1;case MALE:return 2;default:return 3;}}
}

将这几个类反编译下:

// SexEnum.class
public enum SexEnum {MALE(1, "男"),FEMALE(0, "女");private int type;private String name;// $FF: synthetic fieldprivate static final SexEnum[] $VALUES = new SexEnum[]{MALE, FEMALE};private SexEnum(int var3, String var4) {this.type = var3;this.name = var4;}}// Sex1Enum.class
public enum Sex1Enum {MALE("男"),FEMALE("女");private String name;// $FF: synthetic fieldprivate static final Sex1Enum[] $VALUES = new Sex1Enum[]{MALE, FEMALE};private Sex1Enum(String var3) {this.name = var3;}}

反编译这两个枚举类,发现其中多了一个 $VALUES 数组,内部包含了所有的枚举值。继续反编译测试类:

// SwitchTest$1.class
import com.example.express.test.Sex1Enum;
import com.example.express.test.SexEnum;// $FF: synthetic class
class SwitchTest$1 {// $FF: synthetic fieldstatic final int[] $SwitchMap$com$example$express$test$SexEnum;// $FF: synthetic fieldstatic final int[] $SwitchMap$com$example$express$test$Sex1Enum = new int[Sex1Enum.values().length];static {try {$SwitchMap$com$example$express$test$Sex1Enum[Sex1Enum.FEMALE.ordinal()] = 1;} catch (NoSuchFieldError var4) {;}try {$SwitchMap$com$example$express$test$Sex1Enum[Sex1Enum.MALE.ordinal()] = 2;} catch (NoSuchFieldError var3) {;}$SwitchMap$com$example$express$test$SexEnum = new int[SexEnum.values().length];try {$SwitchMap$com$example$express$test$SexEnum[SexEnum.MALE.ordinal()] = 1;} catch (NoSuchFieldError var2) {;}try {$SwitchMap$com$example$express$test$SexEnum[SexEnum.FEMALE.ordinal()] = 2;} catch (NoSuchFieldError var1) {;}}
}

首先生成了一个名为 SwitchTest$1.java 的链接类,里面定义了两个枚举数组,这两个数组元素添加的顺序完全和测试类中 switch 类调用的顺序一致。

图片

枚举元素在数组中的下标由 ordinal() 函数决定,该方法就是返回枚举元素在枚举类中的序号。

这里我们其实就已经知道了,在 switch 语句中,是根据枚举元素在枚举中的序号来转变成 int 型的。最后再看下测试类的反编译结果验证下:

// SwitchTest.class
import com.example.express.test.Sex1Enum;
import com.example.express.test.SexEnum;
import com.example.express.test.SwitchTest.1;public class SwitchTest {public int enumSwitch(SexEnum var1) {switch(1.$SwitchMap$com$example$express$test$SexEnum[var1.ordinal()]) {case 1:return 1;case 2:return 2;default:return 3;}}public int enum1Switch(Sex1Enum var1) {switch(1.$SwitchMap$com$example$express$test$Sex1Enum[var1.ordinal()]) {case 1:return 1;case 2:return 2;default:return 3;}}
}

三、String 类型是咋变成 int 类型的?

首先我们先知道 char 类型是如何变成 int 类型的,很简单,是 ASCII 码,例如存在 switch 语句:

public int charSwitch(char c) {switch (c) {case 'a':return 1;case 'b':return 2;default:return Integer.MAX_VALUE;}
}

反编译结果为:

public int charSwitch(char var1) {switch(var1) {case 97:return 1;case 98:return 2;default:return Integer.MAX_VALUE;}
}

那么对于 String 来说,利用的就是 hashCode() 函数了,但是 两个不同的字符串 hashCode() 是有可能相等的,这时候就得靠 equals() 函数了,例如存在 switch 语句:

public int stringSwitch(String ss) {switch (ss) {case "ABCDEa123abc":return 1;case "ABCDFB123abc":return 2;case "helloWorld":return 3;default:return Integer.MAX_VALUE;}
}

其中字符串 ABCDEa123abc 和 ABCDFB123abc 的 hashCode 是相等的,反编译结果为:

public int stringSwitch(String var1) {byte var3 = -1;switch(var1.hashCode()) {case -1554135584:if(var1.equals("helloWorld")) {var3 = 2;}break;case 165374702:if(var1.equals("ABCDFB123abc")) {var3 = 1;} else if(var1.equals("ABCDEa123abc")) {var3 = 0;}}switch(var3) {case 0:return 1;case 1:return 2;case 2:return 3;default:return Integer.MAX_VALUE;}
}

可以看到它引入了局部变量 var3,对于 hashCode 相等情况通过 equals() 方法判断,最后再判断 var3 的值。

四、它们的包装类型支持吗?

这里以 Integer 类型为例,Character 和 Byte 同理,例如存在 switch 语句:

public int integerSwitch(Integer c) {switch (c) {case 1:return 1;case 2:return 2;}return -1;
}

反编译结果为:

public int integerSwitch(Integer var1) {switch(var1.intValue()) {case 1:return 1;case 2:return 2;default:return -1;}
}

可以看到,是支持包装类型的,通过自动拆箱解决。

那万一包装类型是 NULL 咋办,首先我们知道 swtich 的 case 是不给加 null 的,编译都通不过,那如果传 null 呢?

答案是 NPE,毕竟实际还是包装类型的拆箱,自然就报空指针了。

图片

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

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

相关文章

STC15F100E单片机模拟串口

文章目录 一、芯片简介二、开发环境三、软件模拟串口参考 一、芯片简介 STC15F100系列单片机是宏晶科技生产的单时钟/机器周期(1T)的单片机,新一代8051单片机,指令代码完全兼容传统8051,但是速度快6-12倍。 内部集成R/C时钟,5MHz…

25、pytest的测试报告插件allure

allure简介 在这里,你将找到使用allure创建、定制和理解测试报告所需的一切。开始让你的测试沟通更清晰,更有影响力。 Allure Report是一个实用程序,它处理由兼容的测试框架收集的测试结果并生成HTML报告。 安装allure 1、确保安装了Java…

【SSM源码】基于JAVA的高校竞赛和考级查询系统

该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等学习内容。 目录 一、项目介绍: 二、文档学习资料: 三、模块截图: 四、开发技术与运行环境: 五、代码展示: 六、数据库表截图&#xff1a…

MISRA C 2012 标准浅析

MISRA(The Motor Industry Software Reliability Association),汽车工业软件可靠性联会; 1994年,英国成立。致力于协助汽车厂商开发安全可靠的软件的跨国协会,其成员包括:AB汽车电子、罗孚汽车、宾利汽车、福特汽车、捷…

js实现动态添加删除表格数据的两种方式

目录 1、通过创建节点实现 css代码 html代码 js代码 完整代码 2、通过渲染表格,事件委托实现 css代码 html代码 js代码 完整代码 效果图 1、通过创建节点实现 思路:先把整体的html结构写出来,table表格分为3部分,其中t…

HNU-电路与电子学-2021期末A卷(不含解析)

【写在前面】 电路与电子学好像是从2020级开设的课程,故实际上目前只有2020与2021两个年级考过期末考试。 本份卷子的参考性很高,这是2020级的期末考卷。题目都是很典型的,每一道题都值得仔细研究透。 特别注意:看得懂答案跟写得…

逆水行舟!浅谈24届双非本科秋招

逆水行舟!浅谈24届双非本科的秋招 逆水行舟!浅谈24届双非本科的秋招0、背景 -- 写下本文的初衷1、实习 -- 秋招的预备战役1.1 科大讯飞1.2 三七互娱 2、秋招 -- 一场没有硝烟的战争3、总结 -- 做好自己想做的事情 0、背景 – 写下本文的初衷 如题&#…

常用汇编指令集

寄存器 如上是OD展示的寄存器,逐条说明常用的寄存器和标志位含义: EIP:寄存器指向即将要执行的指令的地址(EIP中的地址,就是下一步要执行指令的地址) ESP:里面的内容永远指向堆栈的最顶端 EAX&…

一文详解集合竞价,建议收藏!

集合竞价是指对在规定的一段时间内接受买卖申报一次性集中撮合的竞价方式。沪深市场9:15-9:25及14:57-15:00为集合竞价的时间段。集合竞价的所有交易以同一个价格成交。集合竞价的成交价确定原则是: 1、可实现最大成交量的价格; 2、高于该价格的买入申…

mac苹果笔记本电脑如何强力删除卸载app软件?

苹果电脑怎样删除app?不是把app移到废纸篓就行了吗,十分简单呢! 其实不然,因为在Mac电脑上,删除应用程序只是删除了应用程序的主要组件。大多数时候,系统会有一个相当长的目录,包含所有与应用程…

Java三种代理模式:静态代理、动态代理和CGLIB代理

Java三种代理模式:静态代理、动态代理和CGLIB代理 代理模式 代理模式是23种设计模式种的一种。代理模式是一种结构型设计模式,它允许为其他对象提供一个替代品或占位符,以控制对这个对象的访问。代理模式可以在不修改被代理对象的基础上&am…

C语言之多重循环

目录 二重循环 用break语句强制结束循环 显示图形 绘制等腰直角三角形 多重循环 continue语句 将循环语句的循环体作为循环语句,就可以进行二重、三重循环。这样的循环称为多重循环。 我们先来了解二重循环 二重循环 在之前我们学习到的循环中的程序都比较简…

Java---异常

文章目录 1. 异常概述2. try...catch3. Throwable成员方法4. 编译时异常和运行时异常区别5. 异常处理之throws6. 自定义异常7. throws和throw的区别 1. 异常概述 1. 异常:就是程序中出现了不正常的情况。 2. Error:严重问题,不需要处理。Exce…

【带头学C++】----- 九、类和对象 ---- 9.4 拷贝构造函数、赋值

目录 9.4 拷贝构造函数、赋值 9.4.1 定义拷贝构造函数 9.4.2 拷贝构造和无参构造、有参构造的关系 9.4.3 拷贝构造的几种调用形式 1、旧对象给新对象初始化,调用拷贝构造 2、给对象取别名不会调用拷贝构造 3、普通对象作为函数参数,调用函数时会发…

STM32-GPIO编程

一、GPIO 1.1 基本概念 GPIO(General-purpose input/output)通用输入输出接口 --GP 通用 --I input输入 --o output输出 通用输入输出接口GPIO是嵌入式系统、单片机开发过程中最常用的接口,用户可以通过编程灵活的对接口进行控制,…

ArcGIS提取DEM中的山脉范围

已知数据:DEM文件ASTGTM_N00E118E.img 使用软件:ArcMap 要求:对数据进行操作,提取数据文件中的山脉范围 下面开始操作: 1、 打开ArcMap将DEM文件ASTGTM_N00E118E.img添加到数据框。 2、 接下来我们打开spatial ana…

虚幻学习笔记8—蓝图操作其他虚幻模块

一、前言 蓝图不仅可以相互之间操作和通信,其他的资源、模块也有操作和通信的方法。文本主要针对蓝图和材质、Niagara、编辑器的通信进行讲解。 二、实现 2.1、蓝图和材质 1)首先,在材质蓝图中按住“4鼠标左键”创建一个参数为四维向量的参…

Kafka中的auto-offset-reset配置

Kafka这个服务在启动时会依赖于Zookeeper,Kafka相关的部分数据也会存储在Zookeeper中。如果kafka或者Zookeeper中存在脏数据的话(即错误数据),这个时候虽然生产者可以正常生产消息,但是消费者会出现无法正常消费消息的…

【小工具分享】分享一个小工具---可视化数据结构 (初学者建议收藏)

工具链接: 可视化数据结构 这里支持大量数据结构地演示,相当全面,对于初学数据结构或者想更直观感受某个数据结构地实现有很大帮助,能直观的看到该数据结构的增删改查,帮助我们理解某一数据结构的性能~ 下面我演示一下…

揭秘MQTT:为何它是物联网的首选协议?

文章目录 MQTT 协议简介概览MQTT 与其他协议对比MQTT vs HTTPMQTT vs XMPP 为什么 MQTT 是适用于物联网的最佳协议?轻量高效,节省带宽可靠的消息传递海量连接支持安全的双向通信在线状态感知 MQTT 5.0 与 3.1.1MQTT 服务器MQTT 客户端 MQTT 协议简介 概…