Java中有分支/跳转表吗?

时间:2009-02-13 23:10:59

标签: java branch jump-table

Java是否有类似于分支或跳转表的内容?

分支或跳转表格为according to wikipedia

  

用于描述使用分支指令表将程序控制(分支)转移到程序的另一部分(或可能已动态加载的不同程序)的有效方法的术语。

Java是否有这样的东西,或者我只需要使用if / else if / else或case语句?

9 个答案:

答案 0 :(得分:12)

Java有switch statement,但它是否编译为字节码中的跳转表是依赖于实现的。通常,如果编译器在switch语句中为每个case找到了很好的常量,那么编译器会为你构建一个跳转表。不过,我不确定你应该真正关心它是如何实现的。如果您首先使用Java进行编码,那么您可能很乐意让编译器和JIT为您处理这些事情。

请注意,switch仅适用于整数基元类型和枚举,因此如果您正在使用其他对象类型,则执行需要使用if / else语句(并且您可能不应该使用其他对象类型)或者为了平等而浮动。)

最后,即使枚举引用在技术上是“常量”,一些编译器只会在你打开枚举时生成一个跳转表如果你的switch语句在enum所在的同一个编译单元中定义。否则,它将生成一个if / else链(就像你必须为常规对象做的那样)。有关详细信息,请参阅java.net forums on extending switch usage for Objects

答案 1 :(得分:4)

  

Java是否有这样的东西,或者我只需要使用if / else if / else或case语句?

我认为case语句(用java中的开关)是等价的。

此外,在OOP中,交换机可以编码一次,然后让多态性成为工作。

来自:http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html

alt text

这取决于您的要求。

答案 2 :(得分:3)

  

一个术语,用于描述使用分支指令表将程序控制(分支)转移到程序的另一部分(或可能已动态加载的不同程序)的有效方法。“

传输程序控制的一种方法是调用函数。当你有几个可供选择时,调用正确函数的一种方法是将其从对象类型中键入。这就是所谓的多态性。 Java和其他面向对象语言具有多态性,通过继承(子类化)实现。不确定它是如何在Java中实现的,但是在C ++中(通常是?或总是?)每个对象中的一个指针指向它的类的v表,其中包含指向虚函数的指针。

我严重怀疑缺少用户定义的跳转表会削弱java应用程序的性能。

答案 3 :(得分:2)

是的,绝对。

如果您编写switch语句,那么根据各种事情,交换机将转换为字节码中的tableswitch指令。通常

  • 开关必须依赖于int值
  • 最高的int值和最低的int值不能相差太远

实现这一目标的最简单方法是使用java枚举,它由编译器专门处理。相关文档位于Java Virtual Machine Specification。当然,JIT编译器几乎可以肯定地将它们直接转换为您运行的任何平台的机器代码中的非常快速的开关。

话虽如此,真正的回答你的问题是“当你做机器代码而不是用高级语言编程时,你会担心这种事情。” / p>

答案 4 :(得分:1)

我不相信你在Java中需要那些性能攻击。我将首先集中精力编写可读代码并使用合适的算法 - 这些将提供比您正在讨论的更多的性能优势。

在大多数独立应用程序中,绝大部分时间都花在等待用户做某事上。在大多数Web应用程序中,JVM中运行字节码的时间应该被网络时间,数据库时间或业务逻辑所淹没。

如果您真的担心Java应用程序的部分性能,可以将其转移到JNI代码中并完全绕过Java解释器。

答案 5 :(得分:0)

认为这就是说某些switch语句是如何在“引擎盖下”实现的。

除此之外,你可以使用HashMap<whatever, Method>之类的东西做类似的事情,你使用map.get(something).invoke()。但是这样做有点失败,因为它不会像跳转表一样快,我想不出一个好的情况,OOP编程/多态不会更好,更清洁。

答案 6 :(得分:0)

你所谈论的那种分支/跳转表并不是由Java,C等高级语言直接提供的,而是由机器代码或字节代码中的编译器生成的。换句话说,您的编译器可能会使用它们但您没有看到它们。

答案 7 :(得分:0)

您可以使用枚举来执行此操作。

// doesn't work in c#
enum Switch implements Runnable {
   OPTION1() {
     public void run() {
        // do something.
     }
   },
   OPTION2() {
     public void run() {
        // do something.
     }
   },
   OPTION3() {
     public void run() {
        // do something.
     }
   }
}

Switch option = Switch.valueOf(switchOptionTest);
option .run();
//or
Switch[] options = Switch.values();
Switch option = options[nSwitchOption];
option .run();

答案 8 :(得分:-1)

你可以用反射和存储匿名内部类的通用HashMap来做到这一点,但这将是一个可怕的黑客。

由于本机匿名方法,在C#中做得非常优雅,但在java中却没有。