Java 带字符串的开关不仅仅是语法上的糖吗?
从Java1.7开始,字符串就可以与switch语句一起使用,这让我有些疑惑Java 带字符串的开关不仅仅是语法上的糖吗?,java,string,switch-statement,Java,String,Switch Statement,从Java1.7开始,字符串就可以与switch语句一起使用,这让我有些疑惑switch关于整数值的语句可以转换为跳转表,这比简单地对运行时计算的整数执行if检查要快;可以对字符串进行类似的优化吗?或者这只是语法上的糖分吗?Yes switch with string是一种语法上的糖分。从 1) 开关中的字符串是语法糖,JVM级别没有变化 2) 在内部,它使用equals方法进行比较,这意味着 传递null将抛出java.lang.NullPointerException,因此要小心 那个 3)
switch
关于整数值的语句可以转换为跳转表,这比简单地对运行时计算的整数执行if
检查要快;可以对字符串进行类似的优化吗?或者这只是语法上的糖分吗?Yes switch with string是一种语法上的糖分。从
1) 开关中的字符串是语法糖,JVM级别没有变化
2) 在内部,它使用equals方法进行比较,这意味着
传递null将抛出java.lang.NullPointerException,因此要小心
那个
3) switch语句中的字符串区分大小写,建议仅使用
一个案例,并将输入转换为首选案例,然后再将其传递给
switch语句
同时检查
如果您看到以下示例,请从同一链接:
public class StringInSwitchCase{
public static void main(String[] args) {
String mode = args[0]; switch (mode) {
case "ACTIVE": System.out.println("Application is running on Active mode");
break;
case "PASSIVE": System.out.println("Application is running on Passive mode");
break;
case "SAFE": System.out.println("Application is running on Safe mode");
} } }
以及反编译代码:
import java.io.PrintStream;
public class StringInSwitchCase{
public StringInSwitchCase() { }
public static void main(string args[]) {
String mode = args[0]; String s;
switch ((s = mode).hashCode()) {
default: break;
case -74056953: if (s.equals("PASSIVE")) {
System.out.println("Application is running on Passive mode"); }
break;
case 2537357: if (s.equals("SAFE")) { System.out.println("Application is running on Safe mode"); }
break;
case 1925346054: if (s.equals("ACTIVE")) { System.out.println("Application is running on Active mode"); }
break; } } }
通过使用hashCode()
和equals()
方法,您将发现开关中的字符串起作用
正如所料,它使用hashCode()方法进行切换,并使用equals()方法
验证的方法,这意味着它只是一个语法糖,
而不是内置的本机功能。
编译器使用
hashCode()
方法基于字符串值优化switch
语句,然后在字节码中使用查找表。这通常比if
-else
语句更有效
例如,以下各项:
String string = "x";
switch(string) {
case "x": System.out.println("x");
break;
case "y": System.out.println("y");
break;
case "z": System.out.println("z");
break;
}
被转换为该字节码:
ldc "x"
astore_1
aload_1
astore_2
iconst_m1
istore_3
aload_2
invokevirtual java/lang/String/hashCode()I
tableswitch 120
10
17
24
default: 30
aload_2
ldc "x"
invokevirtual java/lang/String/equals(Ljava/lang/Object;)Z
ifeq 30
iconst_0
istore_3
goto 30
aload_2
ldc "y"
invokevirtual java/lang/String/equals(Ljava/lang/Object;)Z
ifeq 30
iconst_1
istore_3
goto 30
aload_2
ldc "z"
invokevirtual java/lang/String/equals(Ljava/lang/Object;)Z
ifeq 30
iconst_2
istore_3
iload_3
tableswitch 0
32
36
40
default: 43
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "x"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
goto 43
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "y"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
goto 43
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "z"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
return
String
开关似乎是使用一个固定大小的映射来实现的,这会导致少量项目的对数性能。看到这里的最后两条语句,我觉得很矛盾:如果需要创建一个新的大写/小写字符串来使用它,字节码效率的差异真的那么大吗?所以。。。如果字节码更有效,那么它们就不完全是语法糖。@Jeroenvanevel:-是的,这是矛盾的。我删除了这一部分,并添加了代码以使其更加清晰。也许在这里,我对语法糖的含义产生了疑问。自动装箱是一种语法糖(它只是推断一个方法调用)。Varargs是语法糖(它推断数组的创建)。这有点复杂。编译器计算哈希值并生成case语句。如果两个条件具有相同的哈希代码,则会得到If/else/else-If语句。这感觉比简单的语法糖要多一些。为什么这样会更有效率呢?打开基本上随机的键不能使用跳转表。在最坏的情况下,跳转表将需要2^32个条目。@usr即使跳转表不能使用,即使开关对整数值执行一系列if-else检查,这通常比对字符串值执行一系列if-else检查要便宜。