简体   繁体   English

为什么你的 switch 语句数据类型不能很长,Java?

[英]Why can't your switch statement data type be long, Java?

Here's an excerpt from Sun's Java tutorials :以下是Sun 的 Java 教程的摘录:

A switch works with the byte , short , char , and int primitive data types.开关适用于byteshortcharint原始数据类型。 It also works with enumerated types (discussed in Classes and Inheritance) and a few special classes that "wrap" certain primitive types: Character , Byte , Short , and Integer (discussed in Simple Data Objects).它还适用于枚举类型(在类和继承中讨论)和一些“包装”某些原始类型的特殊类: CharacterByteShortInteger (在简单数据对象中讨论)。

There must be a good reason why the long primitive data type is not allowed.不允许long原始数据类型必须有充分的理由。 Anyone know what it is?有人知道这是什么吗?

I think to some extent it was probably an arbitrary decision based on typical use of 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). 交换机基本上可以通过两种方式实现(或者原则上是组合):对于少数情况,或者其值大范围分散的情况,交换机基本上等同于临时变量上的一系列ifs(打开的值必须只评估一次)。 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. 对于或多或少连续值的中等数量的情况,使用切换表(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). 但是我认为将指令集和编译器的复杂性与实际需求进行平衡可能只是一个实际的决定:你真正需要切换很长时间的情况很少见,因此必须重新编写为一系列的IF语句,或以其他方式工作(如果有问题的长值靠得很近,你可以在你的Java代码中切换int减去最低值的结果)。

Because they didn't implement the necessary instructions in the bytecode and you really don'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, 2³² is a lot of cases and any program with a method long enough to hold more than that is going to be utterly horrendous! 确切地说,2,32是很多情况下,任何方法都有足够长的时间来容纳更多的东西,这将是非常可怕的! 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. (我知道的任何语言的任何代码最长功能略微超过6K SLOC -是的,这是一个很大的switch -这是真的无法控制。)如果你真的坚持与具有正long ,你应该只有一个int或者更少,那么你有两个真正的选择。

  1. Use some variant on the theme of hash functions to compress the long into an int . 在散列函数的主题上使用一些变体将long压缩为int 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. 但实际上,这仍然很可怕,因为它没有解决许多案件的真正问题。

  2. 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. 如果您正在处理大量案例,那么更好的解决方案是将您的设计更改为使用Map<Long,Runnable>或类似的东西,以便您查找如何分派特定值。 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. FWIW,我多年前做过这个(我们在项目中转换到新发布的J2SE 1.2部分)来构建用于模拟大规模并行硬件的自定义字节码引擎(不,重复使用JVM因为从根本上不合适)所涉及的不同的值和执行模型)并且它极大地简化了代码的C版本所使用的大型switch的代码。

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. 要重申带回家的消息,想要switch一个long消息表明你的程序中的类型错误,或者你正在构建一个涉及你应该使用类的那么多变化的系统。 Time for a rethink in either case. 在任何一种情况下重新考虑的时间。

因为查找表索引必须是32位。

Its just happened to me that I come across this 12 years old question and I can provide one of the best solutions to this problem ie use the latest jdk because long and Long are now supported in switch-case statement.我碰巧遇到了这个 12 岁的问题,我可以为这个问题提供最好的解决方案之一,即使用最新的 jdk,因为 long 和 Long 现在在 switch-case 语句中得到支持。 :) :)

A long, in 32bit architectures, is represented by two words . 长的32位体系结构由两个单词表示 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! 现在,想象一下如果由于同步不足会发生什么情况,switch语句的执行会观察到一次写入时高32位,另一次写入低32位! 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! 即使两个写入代表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 reason not to ever have a switch on longs (and as long -pun intended- there will be 32bit machines, this reason will remain valid). 当然,我不知道实际的原因(已经超过15年,我没有注意那么久!),但是如果你意识到这样一个结构可能是多么不安全和不可预测,你会同意的这是一个绝对非常好的理由永远不会切换多头(并且由于长打算 - 将会有32位机器,这个原因仍然有效)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM