JDK 7 中的语法增强 -- (3) swith 里用 String 类型

java 在 switch 语句这一项上更多的是承袭了 c++,其实整个语法就是 c 风格的。java 的 switch 里只能用 byte、char、short、int 和 enum 类型,连 long 型都不能用(因为 switch 里的要被转换为 int  型,而 long 太长了)。要说不支持 float 和 double 那样的浮点那好理解,因为它们本身是不精确的,1 可能是 0.9999999999。boolean 就两值,放 switch 里无意义,因为 c++ 的 switch 里可用bool 型,但在 java 中遭摈弃。

现在在 jdk7 里 switch 可以用字符串了,学了 c#,字符串的好处就是它是表意的,像 switch(action) case "create" : ...; case "delete" : .....,多写意啊,再也不用先定义一堆常量,然后再 switch(action) case Constants.ACTION_CREATE : ......; case Constants.ACTION_DELETE : ......,当然写过不少程序的尽量会避免写成 case 1... case 2 这样的写法了,会让人不知所以的。常量放在 case 中就要求我们经常要去查它定义的值是什么。

虽然 switch 里可以用字符串了,我想还是应该谨慎些,别搞得以后不易查错,看看:



原文中只是说字符串吗,会使用 equals() 方法来比较,然后决定程序的分支走向,并且字符串是区分大小写的,java 编译器对 switch 生成的字节码执行效率上要高于 if-then-else 语句。

为了加深对 switch 中引入字符串支持的理解,我们再进一步,用例子来看看到底发生了什么,java 代码如下:

由它相应的字节码来帮助理解:

在 main() 方法中的 switch 语句,判断的是 int 型,与原来的处理办法是一样,是什么值就跳到哪个指令,只会生成一个 lookupswitch 指令。

而在 foo() 方法中的 switch 语句,判断的是字符串,我们看到启用了两条 lookupswitch 指令来支持这一特性,怎么理解它呢?分两步走,从字节码来看似乎有些画蛇添足。

首先它把 case 中的字符串用 hashCode() 算了一些,生成一条 lookupswitch 指令,就是上面的:

  8: invokevirtual #4                  // Method java/lang/String.hashCode:()I
 11: lookupswitch  { // 2
               51: 36
               52: 50
          default: 61
     }

"3" 和 "4" 的 hashCode 分别是 51 和 52,其实这里应该可以像对待整数一样看待字符串,只需要全部转换为相应的 hashCode 即可。不过上面的字令没有那么直接,而是根据传入的 switch 参数,通过 equase() 方法来判断,对原来的 switch 语句重新设定基于 0 开始的整数为参数,也就是对原来的每一个 case 字符串全部转换为整数 0、1、2 ......,最后全部进入到新的 lookupswitch 语句中,从而实现字符串的 switch 功能。

为什么不直接 hashCode 一步完成了,也许这样的效率会比较高吧。

参考:1. http://download.java.net/jdk7/docs/technotes/guides/language/strings-switch.html

本文链接 https://yanbin.blog/jdk-7-enhance-strings-witch/, 来自 隔叶黄莺 Yanbin Blog

[版权声明] Creative Commons License 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments