Why is this happenning with switch (Java)?
This question already has an answer here:
Can switch statement take objects or not?
No you can't use any arbitrary object in switch statements. This is specified in the language itself. Even String
is only allowed from Java 7 onwards. From JLS §14.11:
The type of the Expression must be char
, byte
, short
, int
, Character
, Byte
, Short
, Integer
, String
, or an enum
type (§8.9), or a compile-time error occurs.
Switch statements with strings are compiled with hashCode comparison, so the code:
switch(s){
case "1":
case "2":
case "3":
}
after compilation looks like:
switch(s.hashCode()){
case "1".hashCode():
case "2".hashCode():
case "3".hashCode():
}
Actually 7th JVM did not add anything specific about working with Strings in switches. Just a little compilation trick. Its possible to compare Strings by hashCode(), because this function is overridden and is based on object's content. This information is present at compile time. While its legal for Strings such approach is absolutely unacceptable for arbitrary object, because hashCode() returns a random number.
That's how it looks in bytecode:
11: tableswitch { // 49 to 51
49: 36 // "1".hashCode()
50: 50 // "2".hashCode()
51: 64 // "3".hashCode()
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 #6 // 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 #7 // 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: 104
2: 104
default: 104
}
104: return
Switch with Strings is compiled to switch with ints. If accidentally two hash codes are equal, strings are compared with equals() method. Compiling switches from JVM specification.
String
is very special in java. String
is designed to be in between a primitive
and a Class
.
Making available to each primitive
, java allowing (from 7) String
also in switch (using **equals**
method internally).
So String
is allowing in switch. But not the every Object.
上一篇: 在Switch语句中使用String?
下一篇: 为什么这是交换(Java)发生的?