Java中switch的实现原理

目前Java中switch语句支持的数据类型包括:byte、short、int、char、String以及Enum,那么switch语句是如何实现的呢?

一、switch对整型的支持

public void switchInt(int value) {
    switch (value) {
        case 1:
            System.out.println("1");
            break;
        case 2:
            System.out.println("2");
            break;
        default:
            System.out.println("Error value");
            break;
    }
}

使用javap -c进行反编译可以看到:

  public void switchInt(int);
    Code:
       0: iload_1
       1: lookupswitch  { // 2
                     1: 28
                     2: 39
               default: 50
          }
      28: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      31: ldc           #14                 // String 1
      33: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      36: goto          58
      39: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      42: ldc           #15                 // String 2
      44: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      47: goto          58
      50: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      53: ldc           #16                 // String Error value
      55: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      58: return

可以看到,switch对整型的支持是直接比较int的值(如果换做byte和short,反编译后是一样的)。

二、switch对char的支持

public void switchChar(char value) {
    switch (value) {
        case 'a':
            System.out.println("a");
            break;
        case 'b':
            System.out.println("b");
            break;
        default:
            System.out.println("Error value");
            break;
    }
}

使用javap -c进行反编译可以看到:

  public void switchChar(char);
    Code:
       0: iload_1
       1: lookupswitch  { // 2
                    97: 28
                    98: 39
               default: 50
          }
      28: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      31: ldc           #17                 // String a
      33: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      36: goto          58
      39: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      42: ldc           #18                 // String b
      44: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      47: goto          58
      50: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      53: ldc           #16                 // String Error value
      55: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      58: return

可以看到,switch对char的支持是将char转换成int值,再做比较的。

三、switch对字符串的支持

public void switchString(String str) {
    switch (str) {
        case "hello":
            System.out.println("hello");
            break;
        case "welcome":
            System.out.println("welcome");
            break;
        default:
            System.out.println("Error value");
            break;
    }
}

使用javap -c进行反编译可以看到:

  public void switchString(java.lang.String);
    Code:
       0: aload_1
       1: astore_2
       2: iconst_m1
       3: istore_3
       4: aload_2
       5: invokevirtual #19                 // Method java/lang/String.hashCode:()I
       8: lookupswitch  { // 2
              99162322: 36
            1233099618: 50
               default: 61
          }
      36: aload_2
      37: ldc           #20                 // String hello
      39: invokevirtual #21                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      42: ifeq          61
      45: iconst_0
      46: istore_3
      47: goto          61
      50: aload_2
      51: ldc           #22                 // String welcome
      53: invokevirtual #21                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      56: ifeq          61
      59: iconst_1
      60: istore_3
      61: iload_3
      62: lookupswitch  { // 2
                     0: 88
                     1: 99
               default: 110
          }
      88: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      91: ldc           #20                 // String hello
      93: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      96: goto          118
      99: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
     102: ldc           #22                 // String welcome
     104: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     107: goto          118
     110: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
     113: ldc           #16                 // String Error value
     115: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     118: return

可以看到,switch对字符串的支持是先比较hashCode,再用equals做校验,最后用得到的值再switch一次。

四、switch对枚举类型的支持

public void switchEnum(State state) {
    switch (state) {
        case Start:
            System.out.println("Start");
            break;
        case InProcessing:
            System.out.println("InProcessing");
            break;
        case Finished:
            System.out.println("Finished");
            break;
        default:
            System.out.println("Error state");
            break;
    }
}

使用javap -c进行反编译可以看到:

  public void switchEnum(pers.wukong.onestep.State);
    Code:
       0: getstatic     #6                  // Field pers/wukong/onestep/Test$1.$SwitchMap$pers$wukong$onestep$State:[I
       3: aload_1
       4: invokevirtual #7                  // Method pers/wukong/onestep/State.ordinal:()I
       7: iaload
       8: tableswitch   { // 1 to 3
                     1: 36
                     2: 47
                     3: 58
               default: 69
          }
      36: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      39: ldc           #9                  // String Start
      41: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      44: goto          77
      47: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      50: ldc           #11                 // String InProcessing
      52: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      55: goto          77
      58: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      61: ldc           #12                 // String Finished
      63: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      66: goto          77
      69: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
      72: ldc           #13                 // String Error state
      74: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      77: return

switch对枚举类型的支持和我预想的不一样,它是维护了一个SwitchMap,枚举的ordinal()方法的返回值作为Key,value是从1开始递增的。switch比较的就是这个value值。

总结

switch其实都是通过int来实现的,不同的是,各种数据类型转换int的方式是不一样的。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。