Why does the switchcase statement in Java work like this?
See the English answer > why can't I switch on a string? 13
Solution
Usually, the problem of language design comes down to "because this is what the designer decides to do" This is just another time
However, Java has some origins in C, and the same is true. In the 1980s, this decision was explained to me, because at that time, the compiler could turn the switch into a jump table: basically, the address of each code block was placed in the table and switch to become a range check, followed by table lookup (usually using the value you passed in to index the array or at least link the array list) to obtain the address, Then jump to the address In this case, only integers make sense Remember, computers are not always as fast as they are now C was designed in the early 1970s based on computers in the late 1960s. Computers are much slower
Some languages in the same syntactic tradition as Java and C (such as JavaScript) make switching just another writing method. If... Else / if... Else, and the type to be checked is not limited to integer type, it may be because it was designed and became a realistic choice in the 1990s Or maybe it's just because the JavaScript Designer (Brendan EICH) likes it
Next, baadshah asked:
First, let's look back at int:
num = Integer.parseInt(args[0]);
switch (num) {
case 1:
System.out.println("You used the special value one");
break;
case 42:
System.out.println("You used the special value forty-two");
break;
case 67:
System.out.println("You used the special value sixty-seven");
break;
default:
System.out.println("You used the a non-special value " + num);
break;
}
The bytecode is generated as follows:
19: iload_2
20: lookupswitch { // 3
1: 56
42: 67
67: 78
default: 89
}
56: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
59: ldc #9 // String You used the special value one
61: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
64: goto 114
67: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
70: ldc #11 // String You used the special value forty-two
72: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
75: goto 114
78: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
81: ldc #12 // String You used the special value sixty-seven
83: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
86: goto 114
89: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
92: new #13 // class java/lang/StringBuilder
95: dup
96: invokespecial #14 // Method java/lang/StringBuilder."":()V
99: ldc #15 // String You used the a non-special value
101: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
104: iload_2
105: invokevirtual #17 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
108: invokevirtual #18 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
111: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
We can see the table lookup in action
So how do you use strings? Then one answer is to convert the switch into an if... Else if... Else structure But they are smarter than this: they use hash codes for optimization, and then use equals to prevent conflicts:
switch (str) {
case "abc":
System.out.println("You used the special value 'abc'");
break;
case "def":
System.out.println("You used the special value 'def'");
break;
case "ghi":
System.out.println("You used the special value 'ghi'");
break;
default:
System.out.println("You used the a non-special value '" + str + "'");
break;
}
Change to:
124: aload 4
126: invokevirtual #19 // Method java/lang/String.hashCode:()I
129: lookupswitch { // 3
96354: 164
99333: 180
102312: 196
default: 209
}
164: aload 4
166: ldc #20 // String abc
168: invokevirtual #21 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
171: ifeq 209
174: iconst_0
175: istore 5
177: goto 209
180: aload 4
182: ldc #22 // String def
184: invokevirtual #21 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
187: ifeq 209
190: iconst_1
191: istore 5
193: goto 209
196: aload 4
198: ldc #23 // String ghi
200: invokevirtual #21 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
203: ifeq 209
206: iconst_2
207: istore 5
209: iload 5
211: tableswitch { // 0 to 2
0: 236
1: 247
2: 258
default: 269
}
236: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
239: ldc #24 // String You used the special value 'abc'
241: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
244: goto 299
247: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
250: ldc #25 // String You used the special value 'def'
252: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
255: goto 299
258: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
261: ldc #26 // String You used the special value 'ghi'
263: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
266: goto 299
269: getstatic #8 // Field java/lang/System.out:Ljava/io/PrintStream;
272: new #13 // class java/lang/StringBuilder
275: dup
276: invokespecial #14 // Method java/lang/StringBuilder."":()V
279: ldc #27 // String You used the a non-special value '
281: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
284: aload_3
285: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
288: ldc #28 // String '
290: invokevirtual #16 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
293: invokevirtual #18 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
296: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
Look what they did there. Now there are basically two switches: one can get a unique number according to the hash code, but double check with the equal sign, and then send the second
