为什么我的switch语句中没有重复的大小写?

Ste*_* B. 2 java compiler-construction compiler-errors

我知道这将无法编译:

int caseNum = 2;

switch(caseNum)
{
    case 2:
        System.out.println("Happy");
        break;
    case 2:
        System.out.println("Birthday");
        break;
    case 2:
        System.out.println("To the ground!");
        break;
    default:
        System.out.println("<3");
        break;
}
Run Code Online (Sandbox Code Playgroud)

我知道case语句是冲突的,并且编译器"不知道我正在谈论哪个'案例2'".我和我的一些同行在幕后想知道冲突是什么,并且听说过switch语句被转换成哈希映射.是这种情况,在编译期间,switch语句是否成为哈希映射,并且映射中的冲突会产生错误?

到目前为止,我已经浏览了Stack Overflow和Google的答案,而且信息必须已经存在,但我不确定如何正确地表达问题.提前致谢!

awk*_*ksp 7

哈希映射只是一个方式,一个switch语句可能会被编译,但在任何情况下,你能想象有重复caseS作为想有多个值在规则相同的密钥HashMap.编译器不知道哪个值对应于键,因此发出错误.

switch 语句也可以编译成跳转表,在这种情况下,由于非常相似的原因,这仍然是模糊的 - 对于相同的跳转位置,您有多种不同的可能性.

switch 语句也可以编译成二进制搜索,在这种情况下,您仍然会遇到相同的问题 - 搜索相同键的多个不同结果.


为了防止你好奇,我做了一个小测试用例,看看javac会编译什么switch.从这个(略微修改)来源:

public static void main(final String[] args) {
    final int caseNum = 2;

    switch (caseNum) {
        case 1:
            System.out.println("Happy");
            break;
        case 2:
            System.out.println("Birthday");
            break;
        case 3:
            System.out.println("To the ground!");
            break;
        default:
            System.out.println("<3");
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

你得到这个字节码:

public static void main(java.lang.String[]);
    Code:
       0: iconst_2      
       1: tableswitch   { // 1 to 3
                     1: 28
                     2: 39
                     3: 50
               default: 61
          }
      28: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      31: ldc           #3                  // String Happy
      33: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      36: goto          69
      39: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      42: ldc           #5                  // String Birthday
      44: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      47: goto          69
      50: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      53: ldc           #6                  // String To the ground!
      55: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      58: goto          69
      61: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      64: ldc           #7                  // String <3
      66: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      69: return        
Run Code Online (Sandbox Code Playgroud)

所以至少对于这个小switch,似乎使用跳转表.我听说开关的编译方式部分取决于它们的大小,但我不知道实现更改的确切位置.20个案例似乎仍被实施为跳转表......


结果表明Stringswitch语句的实现有点不同.从这个来源:

public static void main(final String[] args) {
    final String caseNum = "2";

    switch (caseNum) {
        case "1":
            System.out.println("Happy");
            break;
        case "2":
            System.out.println("Birthday");
            break;
        case "3":
            System.out.println("To the ground!");
            break;
        default:
            System.out.println("<3");
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

你得到这个字节码:

public static void main(java.lang.String[]);
    Code:
       0: ldc           #2                  // String 2
       2: astore_2      
       3: iconst_m1     
       4: istore_3      
       5: aload_2       
       6: invokevirtual #3                  // Method java/lang/String.hashCode:()I
       9: tableswitch   { // 49 to 51
                    49: 36
                    50: 50
                    51: 64
               default: 75
          }
      36: aload_2       
      37: ldc           #4                  // String 1
      39: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      42: ifeq          75
      45: iconst_0      
      46: istore_3      
      47: goto          75
      50: aload_2       
      51: ldc           #2                  // String 2
      53: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      56: ifeq          75
      59: iconst_1      
      60: istore_3      
      61: goto          75
      64: aload_2       
      65: ldc           #6                  // String 3
      67: invokevirtual #5                  // Method java/lang/String.equals:(Ljava/lang/Object;)Z
      70: ifeq          75
      73: iconst_2      
      74: istore_3      
      75: iload_3       
      76: tableswitch   { // 0 to 2
                     0: 104
                     1: 115
                     2: 126
               default: 137
          }
     104: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
     107: ldc           #8                  // String Happy
     109: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     112: goto          145
     115: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
     118: ldc           #10                 // String Birthday
     120: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     123: goto          145
     126: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
     129: ldc           #11                 // String To the ground!
     131: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     134: goto          145
     137: getstatic     #7                  // Field java/lang/System.out:Ljava/io/PrintStream;
     140: ldc           #12                 // String <3
     142: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     145: return
Run Code Online (Sandbox Code Playgroud)

所以你仍然有跳桌,但你有两个.迂回处理后的比特 - 采取的哈希码,开关上,基于负载的情况下的另一常数,并从该做一个"正常"的开关​​(我想).但我想,同样的基本过程呢?