为什么在 Java 7 中,Switch 语句比其他字符串的语句快?

Java 7 中,对象可以位于语句的表达式中。有人可以从官方文件中解释以下声明吗?stringswitch

Java 编译器从使用 String 对象的 switch 语句生成字节码通常比从链接的 if-then-else 语句生成的字节码更有效。


答案 1

Java Code

一个类有两个版本,例如

跟:if-then-else

public class IfThenElseClass {
    public static void main(String[] args) {
        String str = "C";
        if ("A".equals(str)) {

        } else if ("B".equals(str)) {

        } else if ("C".equals(str)) {

        }
    }
}

跟:switch

public class SwitchClass {
    public static void main(String[] args) {
        String str = "C";
        switch (str) {
            case "A":
                break;
            case "B":
                break;
            case "C":
                break;
        }
    }
}

字节码

让我们来看看字节码。获取版本的字节码:if-then-else

Compiled from "CompileSwitch.java"
public class CompileSwitch {
  public CompileSwitch();
    Code:
       0: aload_0
       1: invokespecial #8  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16 // String C
       2: astore_1
       3: ldc           #18 // String A
       5: aload_1
       6: invokevirtual #20 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
       9: ifne          28
      12: ldc           #26 // String B
      14: aload_1
      15: invokevirtual #20 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      18: ifne          28
      21: ldc           #16 // String C
      23: aload_1
      24: invokevirtual #20 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      27: pop
      28: return
}

获取版本的字节码:switch

Compiled from "CompileSwitch.java"
public class CompileSwitch {
  public CompileSwitch();
    Code:
       0: aload_0
       1: invokespecial #8 // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16 // String C
       2: astore_1
       3: aload_1
       4: dup
       5: astore_2
       6: invokevirtual #18 // Method java/lang/String.hashCode:()I
       9: lookupswitch  { // 3
                    65: 44
                    66: 56
                    67: 68
               default: 77
          }
      44: aload_2
      45: ldc           #24 // String A
      47: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      50: ifne          77
      53: goto          77
      56: aload_2
      57: ldc           #30 // String B
      59: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      62: ifne          77
      65: goto          77
      68: aload_2
      69: ldc           #16 // String C
      71: invokevirtual #26 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      74: ifne          77
      77: return
}

结论

  • 在第一个版本中,通过为每个条件调用方法来比较字符串,直到找到它。equals

  • 在第二个版本中,首先获得字符串。然后将其与每个 的值进行比较。请参阅。如果这些值中的任何一个重复,则恰好运行 .否则,请调用绑定的案例的方法。这比仅调用该方法要快得多。hashCodehashCodecaselookupswitchcaseequalsequals


答案 2

switchon 字符串可以更快,原因与字符串哈希集中的查找可能比字符串列表中的查找更快的原因相同:您可以在 中而不是在 中进行查找,其中字符串的数量。O(1)O(N)N

回想一下,这比语句链更有效,因为它是计算的跳转:代码中的偏移量是根据值计算的,然后执行跳转到该偏移量。Java可以使用类似于哈希映射和哈希集中使用的机制在字符串上拉动类似的技巧。switchif-then-else