转到Java字节码

所以有一天,当我查看维基百科页面上的Java字节码时,我遇到了这个例子:

请考虑以下Java代码:

outer: for (int i = 2; i < 1000; i++) { for (int j = 2; j < i; j++) { if (i % j == 0) continue outer; } System.out.println (i); } 

假设将以上内容放在方法中,Java编译器可能会将上面的Java代码转换为字节代码,如下所示:

  0: iconst_2 1: istore_1 2: iload_1 3: sipush 1000 6: if_icmpge 44 9: iconst_2 10: istore_2 11: iload_2 12: iload_1 13: if_icmpge 31 16: iload_1 17: iload_2 18: irem 19: ifne 25 22: goto 38 25: iinc 2, 1 28: goto 11 31: getstatic #84; //Field java/lang/System.out:Ljava/io/PrintStream; 34: iload_1 35: invokevirtual #85; //Method java/io/PrintStream.println:(I)V 38: iinc 1, 1 41: goto 2 44: return 

我注意到goto小字出现了几次,在检查JVM规范时是有效的。 我的问题是为什么? GOTO是Java中保留但不可用的关键字,所以当我们编写和编译java代码时,为什么它似乎是用goto编译回来的。 我想知道这只是在较低级别的编程中总是完成的事情,或者是否因为JVM被信任更有效地使用goto字。 最后我很好奇为什么goto被认为是一种不好的做法,它在java代码中被禁止,但似乎在编译时会直接回到你的代码中。

Java结构化编程function,例如循环( for / while ),在字节码级别使用条件分支( IF.. )和无条件跳转( GOTO )指令实现。

在结构化编程中, breakcontinue外部循环也被认为是足够有用和合法的,Java语言具有这些function(中断/继续标记)。

在JVM /字节码级别,这些也通过GOTO实现。

看到:

您应该区分语言关键字goto和字节代码或汇编指令goto

在高级代码中使用goto跳转是不好的做法,例如在C中。因此在Java中不允许这样做。

关于goto的原始Edsger W. Dijkstra论文 。

在编译代码中使用无条件跳转指令 goto是完全可以的。 它由编译器放在那里,它不会忘记跳转代码的含义,包括数据的初始化,解除分配内存等。

一般背景信息:

任何微处理器的硬件部分只知道它需要从存储器地址开始连续执行每条指令 – 它甚至不知道停止执行指令的存储器地址。

汇编语言是从“命令”到“二进制微指令”的非常薄的转换器。 “命令”列表不包括控制流语句,只有跳转指令(简单跳转或条件跳转),就是它(好吧,有无条件无限循环和条件循环的指令)。

因此,使用这些跳转指令可以实现更高语言(如C)中可用的控制流语句,因为没有其他方法可以实现它们。 正如它所发生的那样,C中的goto被编译成二进制指令,就像一个简单的无条件跳转指令。

Java和JVM原理:

许多不同的硬件架构对于“二进制微指令”和不同的指令集具有不同的标准/格式。 JVM有自己的标准和自己的指令集。

这允许Java编译器始终输出相同的指令,无论可执行文件将在什么硬件体系结构上运行; 将指令从自己的标准转换为当前机器的标准是JVM的工作。

因此,本质上JVM字节码是“java虚拟机”的“汇编语言”。 这意味着它没有控制流指令。 它有无条件的跳转指令(恰好命名为goto )。

在最低级别breakcontinue实现为jump (或goto )。 问题的关键在于,如果你使用更高级别的语言,你可能希望避免使用goto即使它可用(如在C中),并且将使用更易读的控制结构。

有一些特殊情况(在C表示例如),即使是尊重所有“最佳编码实践”的程序员也会使用goto作为例如协程实现。

牺牲编码标准以获得更好或更可靠性能的其他一些示例是,当内核开发人员具有体系结构特定的汇编代码时(C允许您编写汇编指令)。

字节码是虚拟机的某种汇编语言。 在机器语言中使用跳转指令是很常见的。 goto是一个无条件的跳转指令。

Java编译器将方法体内的几乎所有控制流语句转换为goto指令。

goto关键字可能在Java中保留,以保留将其添加到更高版本的选项,以防它的存在本来就是关键的。 从机器的角度来看,goto实际上没有任何问题。 它的声誉很差,因为它允许编写非常难以为人类阅读的代码。 Java语言允许您使用break并继续使用标签作为goto的替代品。

goto在机器级别很好,java编译器不编写代码,它只将代码从java源代码转换为字节码。

对于编写代码的人来说这是一个不同的故事,goto指令很难阅读和分析代码是许多goto跳转后的混乱 。 这就是为什么人们应该使用OO概念而不是跳转指令。

您正在查看JVM等效的机器代码。 Java中是否允许goto与是否允许在字节码中无关,就像JVM字节码中不允许指针一样,但JVM肯定会将字节码编译或解释为使用指针的机器代码。

字节码不是Java,其他语言的程序,如Groovy,可以编译成字节码,你可以使用像BCEL这样的工具直接编写字节码。 至于goto,你不能没有它在低级别。

  1. SpaceTrucker提到了Java语言本身和字节码之间的区别(在对问题的评论中)。 goto关键字和goto指令不一样。 唯一常见的是名字。 在字节码的情况下,它只是JUMPJMP )的指令;
  2. 基本上, goto被认为是编程/编码中的一种不好的做法,因为它实现了’spagetti’代码并且使代码的可读性变差。

编程中的Goto语句是一种方式语句,其中函数调用是双向切换,它将返回到代码的被调用部分。

要使用那些只有字节码,请在其中使用goto。 如果允许用户使用goto意味着我们可能以低效的方式使用它(比如无条件的goto语句),它永远不会让程序终止。

Jvm是如此聪明,永远不会让程序无限运行。