为啥开关(Java)会发生这种情况? [复制]

Posted

技术标签:

【中文标题】为啥开关(Java)会发生这种情况? [复制]【英文标题】:Why is this happenning with switch (Java)? [duplicate]为什么开关(Java)会发生这种情况? [复制] 【发布时间】:2013-12-09 17:55:23 【问题描述】:

很明显 switch 语句可以在 Java 中使用字符串值,类似这样:

String s="diljit"
switch(s)
 ..
 ....

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

switch 语句可以带对象吗?

【问题讨论】:

【参考方案1】:

switch语句可以带对象吗?

不,您不能在 switch 语句中使用任意对象。这是在语言本身中指定的。甚至 String 也只允许从 Java 7 开始。来自JLS §14.11:

表达式的类型必须是charbyteshortintCharacterByteShortInteger、@987654333325@或@9876543324 @type (§8.9),或发生编译时错误。

【讨论】:

补充一下 Rohit 所说的,如果你想根据对象的值进行切换,你可以使用枚举来实现。将你要切换的对象的所有变量放入一个枚举中,根据枚举进行切换。【参考方案2】:

String 在 java 中非常特殊。 String 设计为介于 primitiveClass 之间。

使每个primitive 可用,java 允许(从 7 开始)String 也在 switch 中(内部使用 **equals** 方法)。

所以String 允许切换。但不是每个Object.

【讨论】:

【参考方案3】:

带有字符串的switch语句是用hashCode比较编译的,所以代码:

switch(s)
    case "1":
    case "2":
    case "3":

编译后的样子:

switch(s.hashCode())
    case "1".hashCode():
    case "2".hashCode():
    case "3".hashCode():

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

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

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 编译为使用 int 进行 switch。如果意外地两个哈希码相等,则使用 equals() 方法比较字符串。 Compiling switches 来自 JVM 规范。

【讨论】:

以上是关于为啥开关(Java)会发生这种情况? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥在这种情况下无法访问全局范围? [复制]

为啥会发生这种情况(见图)?

为啥在浮点转换中会发生这种情况?

如果二维数组不是双指针,那么为啥会发生这种情况?

已与其底层 RCW 分离的 COM 对象无法使用 - 为啥会发生这种情况?

为啥当objective-c 有冲突返回类型时会发生这种情况?