1

goto 是 Java 中的关键字, 但还处于保留状态, 在实际的开发中并不能使用. 本文列举了 Java 中的关键字以及引入时间, 同时讨论了和 goto 效果类似的 break label 的语法以及使用的 demo. 最后从将 demo 进行了反编译并逐条分析了 Java 字节码的执行, 得出的结论是 break label 底层比较简单就是一行 goto xx 的字节码指令. 在分析字节码的过程中重温了一下 Java 基于栈实现的执行引擎运行.

原文地址:Java 中有 goto 吗?

欢迎访问我的博客: http://blog.duhbb.com/

Java 关键字

下表中列举了 Java 中的关键字, 这些关键字都不可以作为标识符. constgo 是保留关键字, 虽然没有正式使用, 但是你也不能把它们作为标识符. true, falsenull 虽然看上去像关键字, 但是它们实际上是 literals, 它们也不能作为标识符使用.

abstractcontinuefornewswitch
assert***defaultgoto*packagesynchronized
booleandoifprivatethis
breakdoubleimplementsprotectedthrow
byteelseimportpublicthrows
caseenum****instanceofreturntransient
catchextendsintshorttry
charfinalinterfacestaticvoid
classfinallylongstrictfp**volatile
const*floatnativesuperwhile

备注:

  • *: 未使用
  • **: 1.2 中引入
  • ***:1.4 中引入
  • ****:5.0 中引入

以上来自:Java Language Keywords

可见 Java 中确实有 goto, 但是是保留的关键字, 并不能实际使用.So, 我们不能 goto anywhere.

break label 用法

虽然 Java 中没有 C 语言中 goto 的那种用法, 但是有一个"类似"的.

语法

语法格式: break label, label 你可以自己定义, 只要不冲突就行.

break 语句可以终止带标签的语句的执行; 它并不会将控制流转移到标签上, 而是将控制流立即转移到了带标签语句的下一条语句中.

例子

first:
  for( int i = 0; i < 10; i++) {
    second:
      for(int j = 0; j < 5; j ++ ) {
        break xxx;
      }
  }

third:
  for( int a = 0; a < 10; a++) {

  }
  • xxx 只能是 first 或者 second, 而不能是 third, 也就是只能 break 包裹 break 的语句; break third 会报编译错误.
  • break first 会跳出最外层的 for 循环, 而 break second 则会跳出内层的 for 循环, 外层的 for 循环继续.

查看字节码

源代码:Main.java

public class Main {
    public static void main(String[] args) {
        first:
        for (int i = 0; i < 10; i++) {
            second:
            for (int j = 0; j < 5; j++) {
                System.out.println("i = " + i + ", j = " + j);
                break first;
            }
        }

        third:
        for (int a = 0; a < 10; a++) {
            System.out.println(a);
        }
    }
}

javap -v Main.class 反编译后的字节:

duhbb@debian:/mnt/data/IdeaProjects/test/target/classes$ javap -v Main.class 
Classfile /mnt/data/IdeaProjects/test/target/classes/Main.class
  Last modified 2022-6-8; size 913 bytes
  MD5 checksum f56881b622c0cfceb531278564352491
  Compiled from "Main.java"
public class Main
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #13.#32        // java/lang/Object."<init>":()V
   #2 = Fieldref           #33.#34        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Class              #35            // java/lang/StringBuilder
   #4 = Methodref          #3.#32         // java/lang/StringBuilder."<init>":()V
   #5 = String             #36            // i =
   #6 = Methodref          #3.#37         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #7 = Methodref          #3.#38         // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   #8 = String             #39            // , j =
   #9 = Methodref          #3.#40         // java/lang/StringBuilder.toString:()Ljava/lang/String;
  #10 = Methodref          #41.#42        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #11 = Methodref          #41.#43        // java/io/PrintStream.println:(I)V
  #12 = Class              #44            // Main
  #13 = Class              #45            // java/lang/Object
  #14 = Utf8               <init>
  #15 = Utf8               ()V
  #16 = Utf8               Code
  #17 = Utf8               LineNumberTable
  #18 = Utf8               LocalVariableTable
  #19 = Utf8               this
  #20 = Utf8               LMain;
  #21 = Utf8               main
  #22 = Utf8               ([Ljava/lang/String;)V
  #23 = Utf8               j
  #24 = Utf8               I
  #25 = Utf8               i
  #26 = Utf8               a
  #27 = Utf8               args
  #28 = Utf8               [Ljava/lang/String;
  #29 = Utf8               StackMapTable
  #30 = Utf8               SourceFile
  #31 = Utf8               Main.java
  #32 = NameAndType        #14:#15        // "<init>":()V
  #33 = Class              #46            // java/lang/System
  #34 = NameAndType        #47:#48        // out:Ljava/io/PrintStream;
  #35 = Utf8               java/lang/StringBuilder
  #36 = Utf8               i =
  #37 = NameAndType        #49:#50        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #38 = NameAndType        #49:#51        // append:(I)Ljava/lang/StringBuilder;
  #39 = Utf8               , j =
  #40 = NameAndType        #52:#53        // toString:()Ljava/lang/String;
  #41 = Class              #54            // java/io/PrintStream
  #42 = NameAndType        #55:#56        // println:(Ljava/lang/String;)V
  #43 = NameAndType        #55:#57        // println:(I)V
  #44 = Utf8               Main
  #45 = Utf8               java/lang/Object
  #46 = Utf8               java/lang/System
  #47 = Utf8               out
  #48 = Utf8               Ljava/io/PrintStream;
  #49 = Utf8               append
  #50 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
  #51 = Utf8               (I)Ljava/lang/StringBuilder;
  #52 = Utf8               toString
  #53 = Utf8               ()Ljava/lang/String;
  #54 = Utf8               java/io/PrintStream
  #55 = Utf8               println
  #56 = Utf8               (Ljava/lang/String;)V
  #57 = Utf8               (I)V
{
  public Main();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 5: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LMain;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=3, args_size=1
         0: iconst_0                          // 将常数 0 压入操作数栈
         1: istore_1                          // 将操作数出栈, 并给到本地变量表的第 1 位置的变量, 也就是 i
         2: iload_1                           // 就是变量表中第 1 个位置的 i 压栈到操作数栈顶
         3: bipush        10                  // 把常量 10 压入到操作数栈中
         5: if_icmpge     58                  // 进行比较, 如果为 false 则跳到 58 行 (我猜的)
         8: iconst_0                          // 将常数 0 压入操作数栈
         9: istore_2                          // 将其弹给并给到本地变量表的第 1 位置的变量, 也就是 j
        10: iload_2                           // 就是变量表中第 2 个位置的 i 压栈到操作数栈顶
        11: iconst_5                          // 把常量 5 压入到操作数栈中
        12: if_icmpge     52                  // 进行一通比较, 如果为 false 则跳到 52 行执行
        15: getstatic     #2                  // 获取类的静态字段 Field java/lang/System.out:Ljava/io/PrintStream;
        18: new           #3                  // 创建一个对象, 对象是通过字节索引在常量池中定位的 class java/lang/StringBuilder
        21: dup                               // 复制在栈顶的值
        22: invokespecial #4                  // 调用 StringBuilder 的方法进行初始化 Method java/lang/StringBuilder."<init>":()V
        25: ldc           #5                  // 字符串入栈 String i =
        27: invokevirtual #6                  // 调用 StringBuilder 的 append 方法 Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        30: iload_1                           // 就是变量表中第 1 个位置的 i 压栈到操作数栈顶 这里就是 i 了, 因为准备把 i 拼接到后面去
        31: invokevirtual #7                  // 调用 StringBuilder 的 append Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        34: ldc           #8                  // 字符串入栈 String , j =
        36: invokevirtual #6                  // 调用 StringBuilder 的 append 方法 Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        39: iload_2                           // 就是变量表中第 2 个位置的 j 压栈到操作数栈顶 这里就是 j 了, 因为准备把 j 拼接到后面去
        40: invokevirtual #7                  // 调用 StringBuilder 的 append 方法 Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        43: invokevirtual #9                  // 调用 StringBuilder 的 toString 方法 Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        46: invokevirtual #10                 // 调用 PrintStream 的 println 方法 Method java/io/PrintStream.println:(Ljava/lang/String;)V
        49: goto          58                  // break first 毫无征兆的跳到了 58 行
        52: iinc          1, 1
        55: goto          2
        58: iconst_0                         // 开始了 third 部分的循环
        59: istore_1
        60: iload_1
        61: bipush        10
        63: if_icmpge     79
        66: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        69: iload_1
        70: invokevirtual #11                 // Method java/io/PrintStream.println:(I)V
        73: iinc          1, 1
        76: goto          60
        79: return
      LineNumberTable:
        line 8: 0
        line 10: 8
        line 11: 15
        line 12: 49
        line 8: 52
        line 17: 58
        line 18: 66
        line 17: 73
        line 20: 79
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           10      42     2     j   I
            2      56     1     i   I
           60      19     1     a   I
            0      80     0  args   [Ljava/lang/String;
      StackMapTable: number_of_entries = 6
        frame_type = 252 /* append */
          offset_delta = 2
          locals = [ int ]
        frame_type = 252 /* append */
          offset_delta = 7
          locals = [ int ]
        frame_type = 250 /* chop */
          offset_delta = 41
        frame_type = 250 /* chop */
          offset_delta = 5
        frame_type = 252 /* append */
          offset_delta = 1
          locals = [ int ]
        frame_type = 250 /* chop */
          offset_delta = 18
}
SourceFile: "Main.java"

常量入栈指令有 iconst, bipush, sipush, ldc, ldc2_w 分别对应不同的使用场景, 以下两个表简单总结了使用场景:

  • 八大基本类型场景表
    file
  • 指令场景表
    file

上面的两张图片来自于: Java 逆向基础之常量入栈指令

为啥要这么麻烦, 搞出这么多不通的入栈指令呢? 连 -1~5 这样的都要搞出来?

  • bipush 8 就是把 8 压到操作数栈中.
  • istore_1 就是操作数栈出栈, 存到本地变量表的第 1 位置;
  • iload_1, 就是变量表中第一个位置的 i 压栈到操作数栈顶
  • iinc 1 by 1, 就是变量表中第一个位置的
  • istore_1, 又把栈顶的 8 存回了变量表中的 i
  • dup 关于 dup 指令的作用, 在《深入理解 Java 虚拟机》这本书中是这么描述的. 这是一个操作数栈管理指令, 负责复制栈顶 (注意, 这个栈指的是操作数栈) 一个或者两个数值并将复制值或双份的复制值重新压人栈顶.
    简单理解就是给操作数栈栈顶的元素弄了一个备份.
    那么为什么要进行备份呢?
    一开始是 new 指令在堆上分配了内存并向操作数栈压入了指向这段内存的引用, 之后 dup 指令又备份了一份, 那么操作数栈顶就有两个, 再后是调用 invokespecial #18 指令进行初始化, 此时会消耗一个引用作为传给构造器的 this 参数, 那么还剩下一个引用, 会被 astore_1 指令存储到局部变量表中.dup 来自: Java 字节码 new 之后为什么会有 dup
  • invokespecial 的参数哪儿来的?
  • ldc: 则是从常量池中将常量

Java 字节吗概述

Java 虚拟机采用基于栈的架构, 其指令由操作码和操作数组成.

操作码: 一个字节长度 (0~255), 意味着指令集的操作码个数不能操作 256 条.
操作数: 一条指令可以有零或者多个操作数, 且操作数可以是 1 个或者多个字节. 编译后的代码没有采用操作数长度对齐方式, 比如 16 位无符号整数需使用两个字节储存 (假设为 byte1 和 byte2), 那么真实值是 (byte1 << 8) | byte2.
放弃操作数对齐操作数对齐方案:

优势: 可以省略很多填充和间隔符号, 从而减少数据量, 具有更高的传输效率;Java 起初就是为了面向网络, 智能家具而设计的, 故更加注重传输效率.
劣势: 运行时从字节码里构建出具体数据结构, 需要花费部分 CPU 时间, 从而导致解释执行字节码会损失部分性能.

指令介绍

大多数指令包含了其操作所对应的数据类型信息, 比如 iload, 表示从局部变量表中加载 int 型的数据到操作数栈;而 fload 表示加载 float 型数据到操作数栈. 由于操作码长度只有 1Byte, 因此 Java 虚拟机的指令集对于特定操作只提供有限的类型相关指令, 并非为每一种数据类型都有相应的操作指令. 必要时, 有些指令可用于将不支持的类型转换为可被支持的类型.

对于 byte,short,char,boolean 类型, 往往没有单独的操作码, 通过编译器在编译期或者运行期将其扩展. 对于 byte,short 采用带符号扩展,chart,boolean 采用零位扩展. 相应的数组也是采用类似的扩展方式转换为 int 类型的字节码来处理. 下面分门别类来介绍 Java 虚拟机指令, 都以 int 类型的数据操作为例.

栈是指操作数栈.

这两个部分来自:Jvm 系列 3—字节码指令

字节码指令介绍:

指令含义
aaloadload onto the stack a reference from an array
aastorestore a reference in an array
aconst_nullpush a null reference onto the stack
aloadload a reference onto the stack from a local variable #index
aload_0load a reference onto the stack from local variable 0
aload_1load a reference onto the stack from local variable 1
aload_2load a reference onto the stack from local variable 2
aload_3load a reference onto the stack from local variable 3
anewarraycreate a new array of references of length count and component type identified by the class reference index (indexbyte1 << 8 \indexbyte2) in the constant pool
areturnreturn a reference from a method
arraylengthget the length of an array
astorestore a reference into a local variable #index
astore_0store a reference into local variable 0
astore_1store a reference into local variable 1
astore_2store a reference into local variable 2
astore_3store a reference into local variable 3
athrowthrows an error or exception (notice that the rest of the stack is cleared, leaving only a reference to the Throwable)
baloadload a byte or Boolean value from an array
bastorestore a byte or Boolean value into an array
bipushpush a byte onto the stack as an integer value
breakpointreserved for breakpoints in Java debuggers; should not appear in any class file
caloadload a char from an array
castorestore a char into an array
checkcastchecks whether an objectref is of a certain type, the class reference of which is in the constant pool at index (indexbyte1 << 8 \indexbyte2)
d2fconvert a double to a float
d2iconvert a double to an int
d2lconvert a double to a long
daddadd two doubles
daloadload a double from an array
dastorestore a double into an array
dcmpgcompare two doubles, 1 on NaN
dcmplcompare two doubles, -1 on NaN
dconst_0push the constant 0.0 (a double) onto the stack
dconst_1push the constant 1.0 (a double) onto the stack
ddivdivide two doubles
dloadload a double value from a local variable #index
dload_0load a double from local variable 0
dload_1load a double from local variable 1
dload_2load a double from local variable 2
dload_3load a double from local variable 3
dmulmultiply two doubles
dnegnegate a double
dremget the remainder from a division between two doubles
dreturnreturn a double from a method
dstorestore a double value into a local variable #index
dstore_0store a double into local variable 0
dstore_1store a double into local variable 1
dstore_2store a double into local variable 2
dstore_3store a double into local variable 3
dsubsubtract a double from another
dupduplicate the value on top of the stack
dup_x1insert a copy of the top value into the stack two values from the top. value1 and value2 must not be of the type double or long.
dup_x2insert a copy of the top value into the stack two (if value2 is double or long it takes up the entry of value3, too) or three values (if value2 is neither double nor long) from the top
dup2duplicate top two stack words (two values, if value1 is not double nor long; a single value, if value1 is double or long)
dup2_x1duplicate two words and insert beneath third word (see explanation above)
dup2_x2duplicate two words and insert beneath fourth word
f2dconvert a float to a double
f2iconvert a float to an int
f2lconvert a float to a long
faddadd two floats
faloadload a float from an array
fastorestore a float in an array
fcmpgcompare two floats, 1 on NaN
fcmplcompare two floats, -1 on NaN
fconst_0push 0.0f on the stack
fconst_1push 1.0f on the stack
fconst_2push 2.0f on the stack
fdivdivide two floats
floadload a float value from a local variable #index
fload_0load a float value from local variable 0
fload_1load a float value from local variable 1
fload_2load a float value from local variable 2
fload_3load a float value from local variable 3
fmulmultiply two floats
fnegnegate a float
fremget the remainder from a division between two floats
freturnreturn a float
fstorestore a float value into a local variable #index
fstore_0store a float value into local variable 0
fstore_1store a float value into local variable 1
fstore_2store a float value into local variable 2
fstore_3store a float value into local variable 3
fsubsubtract two floats
getfieldget a field value of an object objectref, where the field is identified by field reference in the constant pool index (indexbyte1 << 8 \indexbyte2)
getstaticget a static field value of a class, where the field is identified by field reference in the constant pool index (indexbyte1 << 8 \indexbyte2)
gotogoes to another instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
goto_wgoes to another instruction at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 \branchbyte2 << 16 \branchbyte3 << 8 \branchbyte4)
i2bconvert an int into a byte
i2cconvert an int into a character
i2dconvert an int into a double
i2fconvert an int into a float
i2lconvert an int into a long
i2sconvert an int into a short
iaddadd two ints
ialoadload an int from an array
iandperform a bitwise AND on two integers
iastorestore an int into an array
iconst_m1load the int value −1 onto the stack
iconst_0load the int value 0 onto the stack
iconst_1load the int value 1 onto the stack
iconst_2load the int value 2 onto the stack
iconst_3load the int value 3 onto the stack
iconst_4load the int value 4 onto the stack
iconst_5load the int value 5 onto the stack
idivdivide two integers
if_acmpeqif references are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
if_acmpneif references are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
if_icmpeqif ints are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
if_icmpgeif value1 is greater than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
if_icmpgtif value1 is greater than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
if_icmpleif value1 is less than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
if_icmpltif value1 is less than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
if_icmpneif ints are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
ifeqif value is 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
ifgeif value is greater than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
ifgtif value is greater than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
ifleif value is less than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
ifltif value is less than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
ifneif value is not 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
ifnonnullif value is not null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
ifnullif value is null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2)
iincincrement local variable #index by signed byte const
iloadload an int value from a local variable #index
iload_0load an int value from local variable 0
iload_1load an int value from local variable 1
iload_2load an int value from local variable 2
iload_3load an int value from local variable 3
impdep1reserved for implementation-dependent operations within debuggers; should not appear in any class file
impdep2reserved for implementation-dependent operations within debuggers; should not appear in any class file
imulmultiply two integers
inegnegate int
instanceofdetermines if an object objectref is of a given type, identified by class reference index in constant pool (indexbyte1 << 8 \indexbyte2)
invokedynamicinvokes a dynamic method and puts the result on the stack (might be void); the method is identified by method reference index in constant pool (indexbyte1 << 8 \indexbyte2)
invokeinterfaceinvokes an interface method on object objectref and puts the result on the stack (might be void); the interface method is identified by method reference index in constant pool (indexbyte1 << 8 \indexbyte2)
invokespecialinvoke instance method on object objectref and puts the result on the stack (might be void); the method is identified by method reference index in constant pool (indexbyte1 << 8 \indexbyte2)
invokestaticinvoke a static method and puts the result on the stack (might be void); the method is identified by method reference index in constant pool (indexbyte1 << 8 \indexbyte2)
invokevirtualinvoke virtual method on object objectref and puts the result on the stack (might be void); the method is identified by method reference index in constant pool (indexbyte1 << 8 \indexbyte2)
iorbitwise int OR
iremlogical int remainder
ireturnreturn an integer from a method
ishlint shift left
ishrint arithmetic shift right
istorestore int value into variable #index
istore_0store int value into variable 0
istore_1store int value into variable 1
istore_2store int value into variable 2
istore_3store int value into variable 3
isubint subtract
iushrint logical shift right
ixorint xor
jsr†jump to subroutine at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \branchbyte2) and place the return address on the stack
jsr_w†jump to subroutine at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 \branchbyte2 << 16 \branchbyte3 << 8 \branchbyte4) and place the return address on the stack
l2dconvert a long to a double
l2fconvert a long to a float
l2iconvert a long to a int
laddadd two longs
laloadload a long from an array
landbitwise AND of two longs
lastorestore a long to an array
lcmppush 0 if the two longs are the same, 1 if value1 is greater than value2, -1 otherwise
lconst_0push 0L (the number zero with type long) onto the stack
lconst_1push 1L (the number one with type long) onto the stack
ldcpush a constant #index from a constant pool (String, int, float, Class, java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, or a dynamically-computed constant) onto the stack
ldc_wpush a constant #index from a constant pool (String, int, float, Class, java.lang.invoke.MethodType, java.lang.invoke.MethodHandle, or a dynamically-computed constant) onto the stack (wide index is constructed as indexbyte1 << 8 \indexbyte2)
ldc2_wpush a constant #index from a constant pool (double, long, or a dynamically-computed constant) onto the stack (wide index is constructed as indexbyte1 << 8 \indexbyte2)
ldivdivide two longs
lloadload a long value from a local variable #index
lload_0load a long value from a local variable 0
lload_1load a long value from a local variable 1
lload_2load a long value from a local variable 2
lload_3load a long value from a local variable 3
lmulmultiply two longs
lnegnegate a long
lookupswitcha target address is looked up from a table using a key and execution continues from the instruction at that address
lorbitwise OR of two longs
lremremainder of division of two longs
lreturnreturn a long value
lshlbitwise shift left of a long value1 by int value2 positions
lshrbitwise shift right of a long value1 by int value2 positions
lstorestore a long value in a local variable #index
lstore_0store a long value in a local variable 0
lstore_1store a long value in a local variable 1
lstore_2store a long value in a local variable 2
lstore_3store a long value in a local variable 3
lsubsubtract two longs
lushrbitwise shift right of a long value1 by int value2 positions, unsigned
lxorbitwise XOR of two longs
monitorenterenter monitor for object ("grab the lock" – start of synchronized() section)
monitorexitexit monitor for object ("release the lock" – end of synchronized() section)
multianewarraycreate a new array of dimensions dimensions of type identified by class reference in constant pool index (indexbyte1 << 8 \indexbyte2); the sizes of each dimension is identified by count1, [count2, etc.]
newcreate new object of type identified by class reference in constant pool index (indexbyte1 << 8 \indexbyte2)
newarraycreate new array with count elements of primitive type identified by atype
nopperform no operation
popdiscard the top value on the stack
pop2discard the top two values on the stack (or one value, if it is a double or long)
putfieldset field to value in an object objectref, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 \indexbyte2)
putstaticset static field to value in a class, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 \indexbyte2)
ret†continue execution from address taken from a local variable #index (the asymmetry with jsr is intentional)
returnreturn void from method
saloadload short from array
sastorestore short to array
sipushpush a short onto the stack as an integer value
swapswaps two top words on the stack (note that value1 and value2 must not be double or long)
tableswitchcontinue execution from an address in the table at offset index
wideexecute opcode, where opcode is either iload, fload, aload, lload, dload, istore, fstore, astore, lstore, dstore, or ret, but assume the index is 16 bit; or execute iinc, where the index is 16 bits and the constant to increment by is a signed 16 bit short
(no name)these values are currently unassigned for opcodes and are reserved for future use

这个是我从 List of Java bytecode instructions 这里扣下来的.

待完成

字节码指令翻译.

原文地址:Java 中有 goto 吗?

欢迎访问我的博客: http://blog.duhbb.com/


tuhooo
1 声望0 粉丝