为什么我的switch语句中没有重复的案例? [英] Why can't I have a duplicate case in my switch statement?
问题描述
我知道这将无法编译:
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 case
s 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屋!