为什么我的switch语句中没有重复的案例? [英] Why can't I have a duplicate case in my switch statement?

查看:90
本文介绍了为什么我的switch语句中没有重复的案例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这将无法编译:

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;
}

我知道case语句有冲突,并且编译器不会知道我在说哪个案例2。我和我的一些同伴在后台想知道冲突是什么,并听说switch语句已转换为哈希映射。是这种情况,在编译时switch语句是否会成为哈希映射,并且映射中的冲突会导致错误?

I know that the case statements are conflicting and that the compiler "doesn't know which 'case 2' I am talking about". A few peers of mine and myself were wondering behind the scenes what the conflict is and had heard that switch statements are converted into hash-maps. Is that the case, does a switch statement become a hash-map during compile time and the conflict in the mapping create the error?

到目前为止,我一直在Stack Overflow和Google周围寻找答案,信息必须已经存在,但是我不确定如何正确表达问题。出现。

So far I have looked around Stack Overflow and Google for an answer, and the information must be out there already, but I am unsure how to express the question correctly it would appear. Thanks in advance!

推荐答案

哈希映射只是可以编译switch语句的一种方式,但是无论如何,您可以想象有重复的 case s试图在常规的 HashMap 中为同一个键设置多个值。编译器不知道哪个值对应于键,因此会产生错误。

A hash map is just one way that a switch statement could be compiled, but in any case, you can imagine having duplicate cases as trying to have multiple values for the same key in a regular HashMap. The compiler doesn't know which one of the values corresponds to the key, and so emits an error.

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

switch statements could also be compiled into a jump table, in which case this is still ambiguous for a very similar reason -- you have multiple different possibilities for the same jump location.

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

switch statements could also be compiled into a binary search, in which case you still have the same problem -- multiple different results for the same key being searched for.

以防万一您好奇,我做了一个小测试用例,看看什么是 javac 会将开关编译为。从以下来源(略作修改):

Just in case you were curious, I did a small test case to see what javac would compile the switch to. From this (slightly modified) source:

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;
    }
}

您将获得以下字节码:

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        

所以至少对于这个小的开关 ,似乎使用了跳转表。我听说开关的编译方式部分取决于它们的大小,但我不知道实现会发生变化的确切时间。

So at least for this small switch, a jump table seems to be used. I have heard that the way switches are compiled depends partly on their size, but I don't know the exact point at which the implementation changes. 20 cases still seem to be implemented as a jump table...

结果 String switch语句的实现略有不同。从这个来源:

Turns out String switch statements are implemented a bit differently. From this source:

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;
    }
}

您将获得以下字节码:

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

所以您仍然有跳转表,但是有两个表。回旋过程的一点点-使用哈希码,根据大小写加载该值,再打开另一个常量,然后从中进行正常切换(我认为)。但是我想是相同的基本过程吗?

So you still have jump tables, but you have two. Bit of a roundabout process -- take the hash code, switch on that, based on the case load another constant, and from that do a "normal" switch (I think). But same basic process, I suppose?

这篇关于为什么我的switch语句中没有重复的案例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆