6

Java是否有类似于分支或跳转表的东西?

根据维基百科,分支或跳转表是

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

Java 是否有类似的东西,还是我只需要使用 if/else if/else 或 case 语句?

4

9 回答 9

13

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

请注意,switch 仅适用于整数原始类型和枚举,因此如果您使用其他对象类型,则确实需要使用 if/else 语句(并且您可能不应该比较双精度数或浮点数是否相等)。

最后,即使枚举引用在技术上是“恒定的”,但如果您的 switch 语句位于定义枚举的同一编译单元中,则某些编译器只会在您打开枚举时为您生成跳转表。否则,它将为您生成一个 if/else 链(就像您对常规对象所做的那样)。有关详细信息,请参阅java.net 论坛上扩展对象的开关使用

于 2009-02-13T23:15:04.453 回答
4

Java 是否有类似的东西,还是我只需要使用 if/else if/else 或 case 语句?

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

此外,在 OOP 中,可以对开关进行一次编码,然后让多态性工作。

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

替代文字

这取决于您的要求。

于 2009-02-13T23:23:52.200 回答
3

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

转移程序控制的一种方法是调用函数。当您有多个可供选择时,调用正确函数的一种方法是将其与对象的类型分开。这叫做多态性。Java 和其他面向对象的语言具有多态性,通过继承(子类化)实现。不确定它是如何在 Java 中实现的,但在 C++ 中(通常?或总是?)每个对象中都有一个指针,指向它的类的 v-table,其中包含指向虚函数的指针。

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

于 2009-02-13T23:29:05.527 回答
2

是的,一点没错。

如果您编写 switch 语句,则根据各种情况,switch 将转换为字节码中的 tableswitch 指令。一般来说

  • 开关必须依赖于一个 int 值
  • 最高 int 值和最低 int 值不能相距太远

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

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

于 2009-02-15T10:19:56.190 回答
1

我不相信你需要 Java 中的那种性能技巧。我会首先专注于编写可读代码和使用体面的算法——这些将提供比您正在讨论的更多的性能优势。

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

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

于 2009-02-13T23:16:12.577 回答
0

You can use enum to do this.

// 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();
于 2009-02-14T07:56:19.130 回答
0

认为这就是一些 switch 语句是如何“在幕后”实现的。

除此之外,您可以HashMap<whatever, Method>使用类似的东西来做类似的事情map.get(something).invoke()。但这有点违背了目的,因为它不会像跳转表那样快,而且我想不出一个好的案例,即 OOP 编程/多态不会更好、更清洁地完成工作。

于 2009-02-13T23:16:23.623 回答
0

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

于 2009-02-13T23:21:24.280 回答
-1

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

由于本机匿名方法,在 C# 中执行此操作非常优雅,但在 java 中则不然。

于 2009-02-13T23:20:16.093 回答