为什么你的 switch 语句数据类型不能很长,Java?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2676210/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why can't your switch statement data type be long, Java?
提问by Fostah
Here's an excerpt from Sun's Java tutorials:
这是Sun 的 Java 教程的摘录:
A switch works with the
byte
,short
,char
, andint
primitive data types. It also works with enumerated types (discussed in Classes and Inheritance) and a few special classes that "wrap" certain primitive types:Character
,Byte
,Short
, andInteger
(discussed in Simple Data Objects).
一种开关用的工作原理
byte
,short
,char
,和int
原始数据类型。它还与枚举类型(在类和继承讨论)和少数特殊类作品是“包装”某些基本类型:Character
,Byte
,Short
,和Integer
(在简单的数据对象讨论)。
There must be a good reason why the long
primitive data type is not allowed. Anyone know what it is?
long
不允许使用原始数据类型必须有充分的理由。有人知道这是什么吗?
采纳答案by Neil Coffey
I think to some extent it was probably an arbitrary decision based on typical use of switch.
我认为在某种程度上,这可能是基于 switch 的典型使用的任意决定。
A switch can essentially be implemented in two ways (or in principle, a combination): for a small number of cases, or ones whose values are widely dispersed, a switch essentially becomes the equivalent of a series of ifs on a temporary variable (the value being switched on must only be evaluated once). For a moderate number of cases that are more or less consecutive in value, a switch table is used (the TABLESWITCH instruction in Java), whereby the location to jump to is effectively looked up in a table.
切换本质上可以通过两种方式(或原则上,组合)实现:对于少数情况,或值广泛分散的情况,切换本质上相当于临时变量上的一系列 ifs(被打开的值只能被评估一次)。对于值或多或少连续的中等数量的情况,使用切换表(Java 中的 TABLESWITCH 指令),从而有效地在表中查找要跳转到的位置。
Either of these methods could in principle use a long value rather than an integer. But I think it was probably just a practical decision to balance up the complexity of the instruction set and compiler with actual need: the cases where you really need to switch over a long are rare enough that it's acceptable to have to re-write as a series of IF statements, or work round in some other way (if the long values in question are close together, you can in your Java code switch over the int result of subtracting the lowest value).
这些方法中的任何一种原则上都可以使用长值而不是整数。但我认为这可能只是一个实际的决定来平衡指令集和编译器的复杂性与实际需要:您真正需要切换 long 的情况很少见,以至于不得不重新编写为一系列 IF 语句,或以其他方式工作(如果有问题的 long 值靠近在一起,您可以在 Java 代码中切换减去最低值的 int 结果)。
回答by Donal Fellows
Because they didn't implement the necessary instructions in the bytecode and you reallydon't want to write that many cases, no matter how "production ready" your code is...
因为他们没有在字节码中实现必要的指令,而且你真的不想写那么多案例,无论你的代码多么“生产就绪”......
[EDIT: Extracted from comments on this answer, with some additions on background]
[编辑:摘自对此答案的评论,并在背景中添加了一些内容]
To be exact, 232 is a lotof cases and any program with a method long enough to hold more than that is going to be utterly horrendous! In any language. (The longest function I know of in any code in any language is a little over 6k SLOC – yes, it's a big switch
– and it's really unmanageable.) If you're really stuck with having a long
where you should have only an int
or less, then you've got two real alternatives.
确切地说,232 是很多情况,任何具有足够长的方法来容纳更多的程序都将是非常可怕的!任何语言。(我所知道的在任何语言的任何代码中最长的函数是略高于 6k SLOC——是的,它很大switch
——而且它真的难以管理。)如果你真的坚持拥有一个long
你应该只有一个int
或更少的地方,那么你有两个真正的选择。
Use some variant on the theme of hash functions to compress the
long
into anint
. The simplest one, only for use when you've got the type wrong, is to just cast! More useful would be to do this:(int) ((x&0xFFFFFFFF) ^ ((x >>> 32) & 0xFFFFFFFF))
before switching on the result. You'll have to work out how to transform the cases that you're testing against too. But really, that's still horrible since it doesn't address the real problem of lots of cases.
A much better solution if you're working with very large numbers of cases is to change your design to using a
Map<Long,Runnable>
or something similar so that you're looking up how to dispatch a particular value. This allows you to separate the cases into multiple files, which is much easier to manage when the case-count gets large, though it does get more complex to organize the registration of the host of implementation classes involved (annotations might help by allowing you to build the registration code automatically).FWIW, I did this many years ago (we switched to the newly-released J2SE 1.2 part way through the project) when building a custom bytecode engine for simulating massively parallel hardware (no, reusing the JVM would not have been suitable due to the radically different value and execution models involved) and it enormously simplified the code relative to the big
switch
that the C version of the code was using.
使用散列函数主题的一些变体
long
将int
. 最简单的一种,仅在类型错误时使用,就是强制转换!更有用的是这样做:(int) ((x&0xFFFFFFFF) ^ ((x >>> 32) & 0xFFFFFFFF))
在打开结果之前。您还必须弄清楚如何转换您正在测试的案例。但实际上,这仍然很可怕,因为它没有解决很多案例的真正问题。
如果您正在处理大量案例,一个更好的解决方案是将您的设计更改为使用 a
Map<Long,Runnable>
或类似的东西,以便您查找如何分派特定值。这允许您将案例分成多个文件,当案例计数变大时,这更容易管理,尽管组织所涉及的实现类主机的注册确实变得更加复杂(注释可能会帮助您自动构建注册码)。FWIW,我在多年前(我们在项目的中途切换到新发布的 J2SE 1.2)时,在构建用于模拟大规模并行硬件的自定义字节码引擎时这样做了(不,重用 JVM 将不适合,因为从根本上涉及不同的价值和执行模型),并且相对于代码
switch
的 C 版本使用的大代码,它极大地简化了代码。
To reiterate the take-home message, wanting to switch
on a long
is an indication that either you've got the types wrong in your program or that you're building a system with that much variation involved that you should be using classes. Time for a rethink in either case.
重申一下重要的信息,想要switch
along
表明您的程序中的类型有误,或者您正在构建一个涉及大量变化的系统,您应该使用类。在这两种情况下都是重新思考的时候了。
回答by JRL
Because the lookup table index must be 32 bits.
因为查找表索引必须是32位的。
回答by Dimitris Andreou
A long, in 32bit architectures, is represented by two words. Now, imagine what could happen if due to insufficient synchronization, the execution of the switch statement observes a long with its high 32 bits from one write, and the 32 low ones from another! It could try to go to ....who knows where! Basically somewhere at random. Even if both writes represented valid cases for the switch statement, their funny combination would probably lead neither to the first nor to the second -- or extremely worse, it could lead to another valid, but unrelated case!
在 32 位体系结构中,long 由两个字表示。现在,想象一下如果由于同步不足,switch 语句的执行在一次写入中观察到一个 long 的高 32 位,以及另一个写入的 32 个低位,会发生什么情况!它可以尝试去......谁知道在哪里!基本上是随机的。即使两个写入都代表了 switch 语句的有效情况,它们有趣的组合可能既不会导致第一个也不会导致第二个——或者更糟糕的是,它可能导致另一个有效但不相关的情况!
At least with an int (or lesser types), no matter how badly you mess up, the switch statement will at least read a value that someone actually wrote, instead of a value "out of thin air".
至少对于 int (或更小的类型),无论您搞砸了多么严重,switch 语句至少会读取某人实际编写的值,而不是“凭空”的值。
Of course, I don't know the actual reason (it's been more than 15 years, I haven't been paying attention that long!), but if you realize how unsafe and unpredictable such a construct could be, you'll agree that this is a definitely very good reasonnot to everhave a switch on longs (and as long -pun intended- there will be 32bit machines, this reason will remain valid).
当然,我不知道真正的原因(已经超过 15 年了,我没有关注那么久!),但是如果您意识到这样的构造是多么不安全和不可预测,您就会同意这是一个绝对很好的理由不要永远对多头开关(而且只要-pun intended-会有32吨的机器,因此仍然有效)。