- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
以下代码返回给定的 String s
是否等于任何其他硬编码字符串。该方法使用 switch
语句来执行此操作:
public class SwitchOnString {
public static boolean equalsAny(String s) {
switch (s) {
case "string 1":
return true;
case "string 2":
return true;
default:
return false;
}
}
}
根据 Java 虚拟机规范 (JMS) 3.10 Compiling Switches "
Compilation of switch statements uses the tableswitch and lookupswitch instructions.
此外
tableswitch and lookupswitch instructions operate only on
int
data.
我阅读了第 3.10 章,但没有找到提到的任何地方 String
。
唯一一个间接接近的句子是:
Other numeric types must be narrowed to type int for use in a switch.
问题一:
此上下文中的 String
也是数字类型吗?还是我错过了什么?
类 SwitchOnString
上的 javap -c
显示:
Compiled from "SwitchOnString.java"
public class playground.SwitchOnString {
public playground.SwitchOnString();
...
public static boolean equalsAny(java.lang.String);
Code:
0: aload_0
1: dup
2: astore_1
3: invokevirtual #16 // Method java/lang/String.hashCode:()I
6: lookupswitch { // 2
1117855161: 32
1117855162: 44
default: 60
}
...
}
显然,hashCode
值用作 case
的 int
键。这可能匹配:
The lookupswitch instruction pairs
int
keys (the values of the case labels) ...
继续 tableswitch 和 lookupswitch JMS 说:
The tableswitch instruction is used when the cases of the switch can be efficiently represented as indices into a table of target offsets. (...) Where the cases of the switch are sparse, the table representation of the tableswitch instruction becomes inefficient in terms of space. The lookupswitch instruction may be used instead.
如果我做对了,那么情况越稀疏,lookupswitch 就越有可能被使用。
问题二:
但是看看字节码:
两个字符串大小写是否足够稀疏以将 switch
编译为 lookupswitch?或者 String
上的每个开关都将编译为 lookupswitch 吗?
最佳答案
规范没有说明如何编译 switch
语句,这取决于编译器。
在这方面,JVMS 声明“其他数字类型必须缩小为 int
类型以用于 switch
”并没有说 Java 编程语言将做这样的转换,也不是 String
或 Enum
是数字类型。 IE。 long
、float
和 double
是数字类型,但不支持将它们与 switch< 一起使用
Java 编程语言中的语句。
所以 language 规范说支持 switch
over String
,因此,编译器必须找到一种方法将它们编译为字节码。使用哈希码等不变属性是一种常见的解决方案,但原则上,也可以使用长度或任意字符等其他属性。
如“Why switch on String compiles into two switches ”和“Java 7 String switch decompiled: unexpected instruction ", javac
当前在编译 switch
over String
值时在字节码级别生成两条 switch 指令(ECJ 也生成两条指令,但细节可能不同).
然后,编译器必须选择一个 lookupswitch
或 tableswitch
操作说明。 javac
在数字不稀疏时确实使用 tableswitch
,但前提是语句有两个以上的 case 标签。
所以当我编译如下方法时:
public static char two(String s) {
switch(s) {
case "a": return 'a';
case "b": return 'b';
}
return 0;
}
我明白了
public static char two(java.lang.String);
Code:
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #9 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 2
97: 36
98: 50
default: 61
}
36: aload_1
37: ldc #10 // String a
39: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 61
45: iconst_0
46: istore_2
47: goto 61
50: aload_1
51: ldc #12 // String b
53: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 61
59: iconst_1
60: istore_2
61: iload_2
62: lookupswitch { // 2
0: 88
1: 91
default: 94
}
88: bipush 97
90: ireturn
91: bipush 98
93: ireturn
94: iconst_0
95: ireturn
但是当我编译的时候,
public static char three(String s) {
switch(s) {
case "a": return 'a';
case "b": return 'b';
case "c": return 'c';
}
return 0;
}
我明白了
public static char three(java.lang.String);
Code:
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #9 // Method java/lang/String.hashCode:()I
8: tableswitch { // 97 to 99
97: 36
98: 50
99: 64
default: 75
}
36: aload_1
37: ldc #10 // String a
39: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 75
45: iconst_0
46: istore_2
47: goto 75
50: aload_1
51: ldc #12 // String b
53: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 75
59: iconst_1
60: istore_2
61: goto 75
64: aload_1
65: ldc #13 // String c
67: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
70: ifeq 75
73: iconst_2
74: istore_2
75: iload_2
76: tableswitch { // 0 to 2
0: 104
1: 107
2: 110
default: 113
}
104: bipush 97
106: ireturn
107: bipush 98
109: ireturn
110: bipush 99
112: ireturn
113: iconst_0
114: ireturn
目前还不清楚为什么 javac
会做出这样的选择。虽然 tableswitch
与 lookupswitch
相比具有更高的基本占用空间(一个额外的 32 位字),但它的字节码仍然更短,即使对于两种 case
标签场景。
但是决策的一致性可以用第二个语句来显示,它总是具有相同的值范围,但编译为 lookupswitch
或 tableswitch
仅取决于标签数量。所以当使用真正的稀疏值时:
public static char three(String s) {
switch(s) {
case "a": return 'a';
case "b": return 'b';
case "": return 0;
}
return 0;
}
编译为
public static char three(java.lang.String);
Code:
0: aload_0
1: astore_1
2: iconst_m1
3: istore_2
4: aload_1
5: invokevirtual #9 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 3
0: 72
97: 44
98: 58
default: 83
}
44: aload_1
45: ldc #10 // String a
47: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
50: ifeq 83
53: iconst_0
54: istore_2
55: goto 83
58: aload_1
59: ldc #12 // String b
61: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
64: ifeq 83
67: iconst_1
68: istore_2
69: goto 83
72: aload_1
73: ldc #13 // String
75: invokevirtual #11 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
78: ifeq 83
81: iconst_2
82: istore_2
83: iload_2
84: tableswitch { // 0 to 2
0: 112
1: 115
2: 118
default: 120
}
112: bipush 97
114: ireturn
115: bipush 98
117: ireturn
118: iconst_0
119: ireturn
120: iconst_0
121: ireturn
对稀疏哈希码使用 lookupswitch
,但对第二个开关使用 tableswitch
。
关于java - String 是关于 switch 的数字类型并且总是编译为 lookupswitch 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51540892/
fiddle :http://jsfiddle.net/rtucgv74/ 我正在尝试将第一个字符与 3 位数字匹配。所以下面的代码应该提醒f234。但反而返回 null ? 源代码: var reg
复制代码 代码如下: Dim strOk,strNo strOk = "12312321$12
我想找 {a number} / { a number } / {a string}模式。我可以得到number / number工作,但是当我添加 / string它不是。 我试图找到的例子: 15
我,我正在做一个模式正则表达式来检查字符串是否是: 数字.数字.数字,如下所示: 1.1.1 0.20.2 58.55541.5221 在java中我使用这个: private static Patt
我有一个字符串,我需要检查它是否在字符串的末尾包含一个数字/数字,并且需要将该数字/数字递增到字符串末尾 +1 我会得到下面的字符串 string2 = suppose_name_1 string3
我正在寻找一个正则表达式 (数字/数字),如(1/2) 数字必须是 1-3 位数字。我使用 Java。 我认为我的问题比正则表达式更深。我无法让这个工作 String s ="(1/15)";
谁能帮我理解为什么我在使用以下代码时会出现类型错误: function sumOfTwoNumbersInArray(a: [number, number]) { return a[0] +
我看到有些人过去也遇到过类似的问题,但他们似乎只是不同,所以解决方案也有所不同。所以这里是: 我正在尝试在 Google Apps 脚本中返回工作表的已知尺寸范围,如下所示: var myRange
我试图了解python中的正则表达式模块。我试图让我的程序从用户输入的一行文本中匹配以下模式: 8-13 之间的数字“/” 0-15 之间的数字 例如:8/2、11/13、10/9 等。 我想出的模式
简单地说,我当前正在开发的程序要求我拆分扫描仪输入(例如:2 个火腿和奶酪 5.5)。它应该读取杂货订单并将其分成三个数组。我应该使用 string.split 并能够将此输入分成三部分,而不管中间字
(number) & (-number) 是什么意思?我已经搜索过了,但无法找到含义 我想在 for 循环中使用 i & (-i),例如: for (i = 0; i 110000 .对于i没有高于
需要将图像ID设置为数字 var number = $(this).attr('rel'); number = parseInt(number); $('#carousel .slid
我有一个函数,我想确保它接受一个字符串,后跟一个数字。并且可选地,更多的字符串数字对。就像一个元组,但“无限”次: const fn = (...args: [string, number] | [s
我想复制“可用”输入数字的更改并将其添加或减去到“总计”中 如果此人将“可用”更改为“3”,则“总计”将变为“9”。 如果用户将“可用”更改为“5”,则“总计”将变为“11”。 $('#id1').b
我有一个与 R 中的断线相关的简单问题。 我正在尝试粘贴,但在获取(字符/数字)之间的断线时遇到问题。请注意,这些值包含在向量中(V1=81,V2=55,V3=25)我已经尝试过这段代码: cat(p
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我在 Typescript 中收到以下错误: Argument of type 'number[]' is not assignable to parameter of type 'number' 我
在本教程中,您将通过示例了解JavaScript 数字。 在JavaScript中,数字是基本数据类型。例如, const a = 3; const b = 3.13; 与其他一些编程语言不同
我在 MDN Reintroduction to JavaScript 上阅读JavaScript 数字只是浮点精度类型,JavaScript 中没有整数。然而 JavaScript 有两个函数,pa
我们在 Excel 中管理库存。我知道这有点过时,但我们正在发展商业公司,我们所有的钱都被困在业务上,没有钱投资 IT。 所以我想知道我可以用Excel自动完成产品编号的方式进行编程吗? 这是一个产品
我是一名优秀的程序员,十分优秀!