为啥开关(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)
..
....
将始终编译.. s 是 String 类型的对象.. 但另一方面 switch 语句不能接受其他类的对象?为什么会发生这种情况,我将如何用合适的答案验证这个问题..
switch 语句可以带对象吗?
【问题讨论】:
【参考方案1】:switch语句可以带对象吗?
不,您不能在 switch 语句中使用任意对象。这是在语言本身中指定的。甚至 String
也只允许从 Java 7 开始。来自JLS §14.11:
表达式的类型必须是
char
、byte
、short
、int
、Character
、Byte
、Short
、Integer
、@987654333325@或@9876543324 @type (§8.9),或发生编译时错误。
【讨论】:
补充一下 Rohit 所说的,如果你想根据对象的值进行切换,你可以使用枚举来实现。将你要切换的对象的所有变量放入一个枚举中,根据枚举进行切换。【参考方案2】:String
在 java 中非常特殊。
String
设计为介于 primitive
和 Class
之间。
使每个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)会发生这种情况? [复制]的主要内容,如果未能解决你的问题,请参考以下文章