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

时间:2014-06-04 20:18:04

标签: 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;
}

我知道案例陈述是冲突的,而且编制者并不知道案件2&#39;我在谈论&#34;。我和我的一些同行在幕后想知道冲突是什么,并且听说过switch语句被转换成哈希映射。是这种情况,在编译期间,switch语句是否成为哈希映射,并且映射中的冲突会产生错误?

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

2 个答案:

答案 0 :(得分:7)

哈希映射只是汇编语句可以编译的一种方式,但无论如何,你可以设想重复case s,试图在常规{{1}中为同一个密钥设置多个值}}。编译器不知道哪个值对应于键,因此发出错误。

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

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


万一你好奇,我做了一个小测试用例,看看switchjavac编译成什么。从这个(稍加修改)来源:

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

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


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

String

你得到这个字节码:

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

所以你仍然有跳桌,但你有两个。一个环形交叉过程的一点 - 取哈希码,打开它,根据案例加载另一个常量,从那里做一个&#34;正常&#34;开关(我想)。但我想,同样的基本过程呢?

答案 1 :(得分:0)

历史上,switch语句可以/可以实现为跳转表(即值到目标地址的映射)。根据表的实现,可能不可能有两个条目用于指向不同地址的相同值。即使有可能,您将如何处理该重复值?从第一个处理程序返回然后转到第二个处理程序?永远不要执行第二个处理程序?

允许这样做是没有意义的。