关于String:为什么这会发生在交换机(Java)上?

Why is this happenning with switch (Java)?

本问题已经有最佳答案,请猛点这里访问。

它非常清楚,开关语句可以在Java中使用字符串值,类似于此:

1
2
3
4
String s="diljit"
switch(s){
 ..
 ....}

将始终编译..s是字符串类型的对象….但是另一方面,switch语句不能接受其他类的对象?为什么会发生这种情况,我如何用合适的答案来验证这个问题。

switch语句是否可以接受对象?


Can switch statement take objects or not?

不,不能在switch语句中使用任意对象。这是在语言本身中指定的。即使是EDCOX1的0度,也只允许从Java 7起。摘自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语句是通过哈希代码比较编译的,因此代码:

1
2
3
4
5
switch(s){
    case"1":
    case"2":
    case"3":
}

编译后如下:

1
2
3
4
5
switch(s.hashCode()){
    case"1".hashCode():
    case"2".hashCode():
    case"3".hashCode():
}

实际上,第7个JVM没有添加任何关于在交换机中使用字符串的具体内容。只是一个小小的编译技巧。它可以通过hashcode()比较字符串,因为此函数被重写并基于对象的内容。此信息在编译时存在。虽然这种方法对于字符串是合法的,但对于任意对象是绝对不可接受的,因为hashcode()返回一个随机数。

这就是它在字节码中的样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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被编译为switch with ints。如果意外地两个哈希代码相等,则将字符串与equals()方法进行比较。根据JVM规范编译交换机。


在Java中,EDCOX1 0是非常特殊的。String设计在primitiveClass之间。

使每个EDCOX1都适用于3,Java允许(从7)EDCOX1,0,也在交换机(内部使用EDCOX1,7,7方法)。

所以String允许在交换机中。但不是每一个Object.