本文主要研究在Java中,switch case语法是如何对String进行支持的
先看原来的代码
public class Test {
public static void main(String[] args) {
String str = "test";
switch (str) {
case "a":
System.out.println("a");
break;
case "b":
System.out.println("b");
break;
case "c":
System.out.println("c");
break;
default:
System.out.println("c");
break;
}
}
}
然后再看反编译之后的代码
public class Test {
public Test() {
}
public static void main(String[] args) {
String str = "test";
byte var3 = -1;
switch(str.hashCode()) {
case 97:
if(str.equals("a")) {
var3 = 0;
}
break;
case 98:
if(str.equals("b")) {
var3 = 1;
}
break;
case 99:
if(str.equals("c")) {
var3 = 2;
}
}
switch(var3) {
case 0:
System.out.println("a");
break;
case 1:
System.out.println("b");
break;
case 2:
System.out.println("c");
break;
default:
System.out.println("c");
}
}
}
在上面我们可以看到,在比较的时候,先是通过hashcode来比较,如果hashcode一样,就再通过equals方法来比较。所以本质上还是没有脱离int比较的原则。
综上所述,java的switch对String的支持,实际上是通过编译器做了一次优化
那么如果两个case的String的hashcode冲突^1了会怎么样呢?比如下面代码:
public class Test {
public static void main(String[] args) throws Exception {
String str = "test";
switch (str) {
case "AaAa":
System.out.println("a");
break;
case "BBBB":
System.out.println("b");
break;
case "AaBB":
System.out.println("c");
break;
default:
System.out.println("c");
break;
}
}
}
再看反编译之后的代码
public class Test {
public Test() {
}
public static void main(String[] args) throws Exception {
String str = "test";
byte var3 = -1;
switch(str.hashCode()) {
case 2031744:
if(str.equals("AaBB")) {
var3 = 2;
} else if(str.equals("BBBB")) {
var3 = 1;
} else if(str.equals("AaAa")) {
var3 = 0;
}
default:
switch(var3) {
case 0:
System.out.println("a");
break;
case 1:
System.out.println("b");
break;
case 2:
System.out.println("c");
break;
default:
System.out.println("c");
}
}
}
}
编译器会在同一个hashcode下面,再通过if else来进行判断。
那么可能还会有一个问题,为什么要分成两步的switch来做呢?其实很简单,方便给编译器定一个规则。我们设想一下,如果不是通过两步switch,那么应该是如下的代码:
public class Test {
public Test() {
}
public static void main(String[] args) throws Exception {
String str = "test";
byte var3 = -1;
switch(str.hashCode()) {
case 2031744:
if(str.equals("AaBB")) {
System.out.println("a");
} else if(str.equals("BBBB")) {
System.out.println("b");
} else if(str.equals("AaAa")) {
System.out.println("c");
}
default:
System.out.println("c");
}
}
}
那么如果我们的case "AaAa":是没有break条件的,那么编译器又要做额外的优化才能达到这个效果,这样子的话,对编译器的编写会十分复杂,不如就分为两步,第一步的switch先计算出要走哪个case,然后再在第二个switch去执行具体的case。
原文:深入理解JAVA中的switch case是如何对String做支持的