java1.7 switch_jdk1.7 String switch的实现

对于int的switch,jvm是用tableswitch和lookupswitch来实现的,jdk1.7 switch增加了对string的支持,那么底层是如何实现的呢?是否增加了新的指令或是否给某些指令增加了新的含义?

看这样一个程序:

Java代码  0b02c719ee76fccc5a0fb8554553304f.png

public class Test {

public static void main(String[] args) {

String name = "b";

int value = 0;

switch(name) {

case "a":

value = 1;

break;

case "b":

value = 2;

break;

case "c":

value = 3;

break;

case "d":

value = 4;

break;

case "e":

value = 5;

break;

default:

value = 6;

}

System.out.println(value);

}

}

javap -c Test得出的结果为:

Java代码  0b02c719ee76fccc5a0fb8554553304f.png

public static void main(java.lang.String[]);

Code:

0: ldc           #2                  // String b

2: astore_1                    //将"b"赋值给name

3: iconst_0                    //将0入栈

4: istore_2                    //将0赋值给value

5: aload_1                 //将name(即"b")入栈

6: astore_3                    //将name(即"b")赋值给一个编译器生成的变量,记为tmpName(tmpName此时也是"b")

7: iconst_m1                   //将-1入栈

8: istore        4         //将-1赋值给一个编译器生成的变量,记为m1

10: aload_3                 //将tmpName(即"b")入栈

11: invokevirtual #3                  // Method java/lang/String.hashCode:()I       调用tmpName的hashCode方法("b".hashCode(),得结果98)

14: tableswitch   { // 97 to 101        //根据hashCode的值到不同的分支

97: 48

98: 63                    //这里走到这个分支,跳转到63

99: 78

100: 93

101: 108

default: 120

}

48: aload_3

49: ldc           #4                  // String a

51: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z

54: ifeq          120

57: iconst_0

58: istore        4

60: goto          120

63: aload_3                         //从14跳转到了这里,将tmpName(即"b")入栈

64: ldc           #2                  // String b       将"b"入栈

66: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z

//比较tmpName和"b",如果相等,将1入栈,不等将0入栈.这里是相等的,入栈的为1

69: ifeq          120                   //从栈顶取出比较结果,如果等于0,就跳到120,如果不等于0就继续下面的指令,这里显然不等于0

72: iconst_1                            //将1入栈

73: istore        4                 //将1存储到m1中

75: goto          120                   //跳到120

78: aload_3

79: ldc           #6                  // String c

81: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z

84: ifeq          120

87: iconst_2

88: istore        4

90: goto          120

93: aload_3

94: ldc           #7                  // String d

96: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z

99: ifeq          120

102: iconst_3

103: istore        4

105: goto          120

108: aload_3

109: ldc           #8                  // String e

111: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z

114: ifeq          120

117: iconst_4

118: istore        4

120: iload         4                 //将m1(即73行存进去的1)的值入栈

122: tableswitch   { // 0 to 4

0: 156

1: 161                   //这里走1这个分支,跳到161

2: 166

3: 171

4: 176

default: 181

}

156: iconst_1

157: istore_2

158: goto          184

161: iconst_2                    //将2入栈

162: istore_2                    //将2存储到value

163: goto          184           //跳转到184进行打印输出

166: iconst_3

167: istore_2

168: goto          184

171: iconst_4

172: istore_2

173: goto          184

176: iconst_5

177: istore_2

178: goto          184

181: bipush        6

183: istore_2

184: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;

187: iload_2

188: invokevirtual #10                 // Method java/io/PrintStream.println:(I)V

191: return

在这一堆指令中我们发现,jdk1.7并没有新指令来处理string switch,还是继续用lookupswitch和tableswitch两个指令来处理的,也没有扩展这两个指令,它们还是只能处理int。

在11行,我们看到调用了需要switch的string的hashCode方法,并对该hashCode进行switch,并跳转到相应的处理指令。跳到新的指令处我们发现这里(63行)将待switch的变量(name)与case中的值("b")equals了一下。这样做是为了避免不同的string有相同的hashCode,确定equals返回true后,编译器生成了一个处理value的switch,源码里有多少个case编译器生成的tableswitch就有多少个分支,最终会找到相应的处理分支完成string switch的处理。

接下来,看一个不同string hashCode相等的版本:

buzzards与righto的hashCode相等

hierarch与crinolines的hashCode相等

这里选择buzzards和righto

Java代码  0b02c719ee76fccc5a0fb8554553304f.png

public class Test {

public static void main(String[] args) {

String name = "buzzards";

int value = 0;

switch(name) {

case "buzzards":

value = 1;

break;

case "righto":

value = 2;

break;

default:

value = 6;

}

System.out.println(value);

}

}

字节码:

Java代码  0b02c719ee76fccc5a0fb8554553304f.png

public static void main(java.lang.String[]);

Code:

0: ldc           #2                  // String buzzards

2: astore_1

3: iconst_0

4: istore_2

5: aload_1

6: astore_3

7: iconst_m1

8: istore        4

10: aload_3

11: invokevirtual #3                  // Method java/lang/String.hashCode:()I

14: lookupswitch  { // 1

-931102253: 32

default: 59

}

32: aload_3

33: ldc           #4                  // String righto

35: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)

38: ifeq          47

41: iconst_1

42: istore        4

44: goto          59

47: aload_3

48: ldc           #2                  // String buzzards

50: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)

53: ifeq          59

56: iconst_0

57: istore        4

59: iload         4

61: lookupswitch  { // 2

0: 88

1: 93

default: 98

}

88: iconst_1

89: istore_2

90: goto          101

93: iconst_2

94: istore_2

95: goto          101

98: bipush        6

100: istore_2

101: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;

104: iload_2

105: invokevirtual #7                  // Method java/io/PrintStream.println:(I)V

108: return

这里我们看到两个字符串都跳到32行,首先跟"righto"比较,如果不相等则跳到47行比较buzzards。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值