当前位置: 首页 > 科技观察

switch是如何支持String的?为什么不支持长?

时间:2023-03-11 20:27:33 科技观察

我们知道JavaSwitch支持byte、short、int类型。在JDK1.5中支持枚举类型,在JDK1.7中支持String类型。那为什么不支持long类型呢?很明显,它是和byte、short、int一样的数值类型。它是如何支持String类型的呢?1、结论不是秘密,先说结论:switch底层使用int类型进行判断,即使是枚举或者String类型,最终都会转为int类型。由于long类型比int类型表示更大的范围,因此不支持long类型。下面详细介绍每种类型是如何转换成int类型的,使用的编译命令是javac。2、枚举类型是怎么变成int类型的?在没有实验之前,我想当然地认为它是根据枚举的int类型字段计算的(因为一般的枚举都是int类型,string类型),但是后来想了想,如果枚举不有一个int类型的字段,如果有多个int字段怎么办,那么肯定不是这样的。让我们看看下面的实验。定义两个枚举类,一个枚举类有一个int类型属性,一个string类型属性,另一个枚举类只有一个string属性:publicenumSexEnum{MALE(1,"Male"),FEMALE(0,"Female");privateinttype;privateStringname;SexEnum(inttype,Stringname){this.type=type;this.name=name;}}publicenumSex1Enum{MALE("male"),FEMALE("female");privateStringname;Sex1Enum(Stringname){this.name=name;}}然后写一个测试类,让两个枚举开关的FEMALE和MALE对应的返回值不同:return2;default:return3;}}publicintenum1Switch(Sex1Enumsex){switch(sex){caseFEMALE:return1;caseMALE:return2;default:return3;}}}反编译这些类://SexEnum.classpublicenumSexEnum{MALE(1,"鐢?"),FEMALE(0,"古?");privateinttype;privateStringname;//$FF:syntheticfieldprivatestaticfinalSexEnum[]$VALUES=newSexEnum[]{MALE,FEMALE};privateSexEnum(intvar3,Stringvar4){这个。type=var3;this.name=var4;}}//Sex1Enum.classpublicenumSex1Enum{MALE("鐢?"),FEMALE("t;组");privateStringname;//$FF:syntheticfieldprivatestaticfinalSex1Enum[]$VALUES=newSex1Enum[]{MALE,FEMALE};privateSex1Enum(Stringvar3){this.name=var3;}}反编译这两个枚举类,发现有是一个额外的$VALUES数组,其中包含所有枚举值继续反编译测试类://SwitchTest$1.classimportcom.example.express.test.Sex1Enum;importcom.example.express.test.SexEnum;//$FF:syntheticclassclassSwitchTest$1{//$FF:syntheticfieldstaticfinalint[]$SwitchMap$com$example$express$test$SexEnum;//$FF:syntheticfieldstaticfinalint[]$SwitchMap$com$example$express$test$Sex1Enum=newint[Sex1Enum.values().length];static{try{$SwitchMap$com$example$express$test$Sex1Enum[Sex1Enum.FEMALE.ordinal()]=1;}catch(NoSuchFieldErrorvar4){;}try{$SwitchMap$com$example$express$test$Sex1Enum[Sex1Enum.MALE.ordinal()]=2;}catch(NoSuchFieldErrorvar3){;}$SwitchMap$com$example$express$test$SexEnum=newint[SexEnum.values().length];try{$SwitchMap$com$example$express$test$SexEnum[SexEnum.MALE.ordinal()]=1;}catch(NoSuchFieldErrorvar2){;}try{$SwitchMap$com$example$express$test$SexEnum[SexEnum.FEMALE.ordinal()]=2;}catch(NoSuchFieldErrorvar1){;}}}首先生成一个名为SwitchTest$1.java的链接类,定义了两个枚举数组,顺序在这两个数组的元素相加的顺序和测试类中调用switch类的顺序是完全一致的。枚举元素在数组中的下标由ordinal()函数确定,该函数返回枚举元素在枚举类中的序号。这里我们其实已经知道,在switch语句中,根据枚举元素在枚举中的序号,将枚举元素转换为int类型。最后查看测试类的反编译结果进行验证://SwitchTest.classimportcom.example.express.test.Sex1Enum;importcom.example.express.test.SexEnum;importcom.example.express.test.SwitchTest.1;publicclassSwitchTest{publicintenumSwitch(SexEnumvar1){switch(1.$SwitchMap$com$example$express$test$SexEnum[var1.ordinal()]){case1:return1;case2:return2;default:return3;}}publicintenum1Switch(Sex1Enumvar1){switch(1.$SwitchMap$com$example$express$test$Sex1Enum[var1.ordinal()]){case1:return1;case2:return2;default:return3;}}}三、String类型如何变为int类型的?首先我们先知道char类型是怎么变成int类型的,很简单,就是ASCII码,比如有一个switch语句:publicintcharSwitch(charc){switch(c){case'a':return1;案例'b':return2;default:returnInteger.MAX_VALUE;}}反编译结果:publicintcharSwitch(charvar1){switch(var1){case97:return1;case98:return2;default:returnInteger.MAX_VALUE;}}那么对于String来说,使用的是hashCode()函数,但是两个不同的字符串hashCode()可能相等,这时候就依赖于equals()函数,比如有switch语句:publicintstringSwitch(Stringss){switch(ss){case"ABCDEa123abc":returnn1;case"ABCDFB123abc":return2;case"helloWorld":return3;default:returnInteger.MAX_VALUE;}}其中字符串ABCDEa123abc和ABCDFB123abc的hashCode相等,反编译结果为:publicintstringSwitch(Stringvar1){bytevar3=-1;switch(var1.hashCode()){case-1554135584:if(var1.equals("helloWorld")){var3=2;}break;case165374702:if(var1.equals("ABCDFB123abc")){var3=1;}elseif(var1.equals("ABCDEa123abc")){var3=0;}}switch(var3){case0:return1;case1:return2;case2:return3;default:returnInteger.MAX_VALUE;}}可以看到引入局部变量var3,通过equals()方法判断hashCode是否相等,最终判断var3的值。另外,关注公众号Java技术栈,后台回复:面试,可以拿到我整理的Java系列面试题及答案,很全。4.他们的包装类型是否支持?这里我们以Integer类型为例,Character和Byte是一样的,比如有一个switch语句:publicintegerSwitch(Integerc){switch(c){case1:return1;case2:return2;}return-1;}反编译结果为:publicintegerSwitch(Integervar1){switch(var1.intValue()){case1:return1;case2:return2;default:return-1;}}可以看出支持封装类型,自动解决拆箱。那么如果包装类型为NULL呢?首先我们知道swtich的case不加null,编译失败。如果传递了null怎么办?答案是NPE。毕竟实际上是对包装类型的拆箱,自然会报空指针。另外,关注公众号Java技术栈,后台回复:面试,可以拿到我整理的Java系列面试题及答案,很全。