在jDK1.6之前传到switch这个关键词里面的参数只能是char和int类型的数据,但是JDK1.7之后,传进switch里面的值可以是String类型。
之前用的时候一直没有想过这个问题,今天有空就一起探索一下这个问题。
我们先看一下传进switch的值为int类型的代码:
int number = 5; switch(number) { case 'c': System.out.println("the case number is c"); break; case 22: System.out.println("the case number is 2"); break; }
将之编译成class文件然后反编译,看这段代码会是怎样的:
int number = 5; switch (number) { case 99: System.out.println("the case number is c"); break; case 22: System.out.println("the case number is 2"); }
可以知道,字符‘c’被编译成了99.这个很容易理解,我们都知道在字符'c'按照Ascii编码规范,‘c’的二进制编码为01100011,转换为十进制就是99.看到这个可能会想,如果跟在case后面的char的二进制和其它case的int相同,会发生什么效果呢?刚试了一下,直接导致的是编译不通过。你们也可以试一下传进去一个char值,看会发生什么问题
char c ='1'; switch(c) { case 'c': System.out.println(); break; case 0: System.out.println(); break; default: }
反编译代码为:
char c = '1'; switch (c) { case 'c': System.out.println(); break; case '\000': System.out.println(); }
对比两段代码,我们不难发现,case后面跟的常量编译之后的形式与switch传进去的值有关,当传进去的是int类型,case后面的常量肯定也会编译成int类型,即使有char类型也会被编译转换为int类型。如果是char类型,则会转换为char类型。
下面我们看一下JDK1.7的switch新特性,如果传进去的是String类型,编译过后的代码是怎样的呢,jdk1.7这个新加的特性,是通过修改jvm还是怎么实现的呢。
我们看一下这段代码:
String str = "123"; switch(str) { case "123": System.out.println(str); break; case "456": System.out.println(str); break; default: System.out.println(str); }
编译之后,反编译得代码如下:
String str = "123"; String str1; switch ((str1 = str).hashCode()) { case 48690: if (str1.equals("123")) { break; } break; case 51669: if (!str1.equals("456")) { break label80; System.out.println(str); break label87; } else { System.out.println(str); } break; }
我们可以看到,其实传进switch的是字符串的hashCode值,而case 后面的字符串常量在编译之后也变成了它的hashCode。而在case后面的模块代码中多了一段比较case后面的字符串常量与传进来的字符串是否相等的判断代码。
在此我们可以看出,jdk1.7的switch新特性,case的常量可以是字符串,传进去的值可以是字符串,其实也是沿用之前的特性,只是在编译的时候将字符串转换为hashcode值对比而已
