goto
是 Java 中的关键字, 但还处于保留状态, 在实际的开发中并不能使用. 本文列举了 Java 中的关键字以及引入时间, 同时讨论了和 goto
效果类似的 break label
的语法以及使用的 demo. 最后从将 demo 进行了反编译并逐条分析了 Java 字节码的执行, 得出的结论是 break label
底层比较简单就是一行 goto xx
的字节码指令. 在分析字节码的过程中重温了一下 Java 基于栈实现的执行引擎运行.
原文地址:Java 中有 goto 吗?
欢迎访问我的博客: http://blog.duhbb.com/
Java 关键字
下表中列举了 Java 中的关键字, 这些关键字都不可以作为标识符. const
和 go
是保留关键字, 虽然没有正式使用, 但是你也不能把它们作为标识符. true
, false
和 null
虽然看上去像关键字, 但是它们实际上是 literals, 它们也不能作为标识符使用.
abstract | continue | for | new | switch |
assert*** | default | goto* | package | synchronized |
boolean | do | if | private | this |
break | double | implements | protected | throw |
byte | else | import | public | throws |
case | enum**** | instanceof | return | transient |
catch | extends | int | short | try |
char | final | interface | static | void |
class | finally | long | strictfp** | volatile |
const* | float | native | super | while |
备注:
*
: 未使用**
: 1.2 中引入***
:1.4 中引入****
:5.0 中引入
可见 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
分别对应不同的使用场景, 以下两个表简单总结了使用场景:
- 八大基本类型场景表
- 指令场景表
上面的两张图片来自于: 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—字节码指令
字节码指令介绍:
指令 | 含义 | |||
---|---|---|---|---|
aaload | load onto the stack a reference from an array | |||
aastore | store a reference in an array | |||
aconst_null | push a null reference onto the stack | |||
aload | load a reference onto the stack from a local variable #index | |||
aload_0 | load a reference onto the stack from local variable 0 | |||
aload_1 | load a reference onto the stack from local variable 1 | |||
aload_2 | load a reference onto the stack from local variable 2 | |||
aload_3 | load a reference onto the stack from local variable 3 | |||
anewarray | create a new array of references of length count and component type identified by the class reference index (indexbyte1 << 8 \ | indexbyte2) in the constant pool | ||
areturn | return a reference from a method | |||
arraylength | get the length of an array | |||
astore | store a reference into a local variable #index | |||
astore_0 | store a reference into local variable 0 | |||
astore_1 | store a reference into local variable 1 | |||
astore_2 | store a reference into local variable 2 | |||
astore_3 | store a reference into local variable 3 | |||
athrow | throws an error or exception (notice that the rest of the stack is cleared, leaving only a reference to the Throwable) | |||
baload | load a byte or Boolean value from an array | |||
bastore | store a byte or Boolean value into an array | |||
bipush | push a byte onto the stack as an integer value | |||
breakpoint | reserved for breakpoints in Java debuggers; should not appear in any class file | |||
caload | load a char from an array | |||
castore | store a char into an array | |||
checkcast | checks whether an objectref is of a certain type, the class reference of which is in the constant pool at index (indexbyte1 << 8 \ | indexbyte2) | ||
d2f | convert a double to a float | |||
d2i | convert a double to an int | |||
d2l | convert a double to a long | |||
dadd | add two doubles | |||
daload | load a double from an array | |||
dastore | store a double into an array | |||
dcmpg | compare two doubles, 1 on NaN | |||
dcmpl | compare two doubles, -1 on NaN | |||
dconst_0 | push the constant 0.0 (a double) onto the stack | |||
dconst_1 | push the constant 1.0 (a double) onto the stack | |||
ddiv | divide two doubles | |||
dload | load a double value from a local variable #index | |||
dload_0 | load a double from local variable 0 | |||
dload_1 | load a double from local variable 1 | |||
dload_2 | load a double from local variable 2 | |||
dload_3 | load a double from local variable 3 | |||
dmul | multiply two doubles | |||
dneg | negate a double | |||
drem | get the remainder from a division between two doubles | |||
dreturn | return a double from a method | |||
dstore | store a double value into a local variable #index | |||
dstore_0 | store a double into local variable 0 | |||
dstore_1 | store a double into local variable 1 | |||
dstore_2 | store a double into local variable 2 | |||
dstore_3 | store a double into local variable 3 | |||
dsub | subtract a double from another | |||
dup | duplicate the value on top of the stack | |||
dup_x1 | insert 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_x2 | insert 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 | |||
dup2 | duplicate top two stack words (two values, if value1 is not double nor long; a single value, if value1 is double or long) | |||
dup2_x1 | duplicate two words and insert beneath third word (see explanation above) | |||
dup2_x2 | duplicate two words and insert beneath fourth word | |||
f2d | convert a float to a double | |||
f2i | convert a float to an int | |||
f2l | convert a float to a long | |||
fadd | add two floats | |||
faload | load a float from an array | |||
fastore | store a float in an array | |||
fcmpg | compare two floats, 1 on NaN | |||
fcmpl | compare two floats, -1 on NaN | |||
fconst_0 | push 0.0f on the stack | |||
fconst_1 | push 1.0f on the stack | |||
fconst_2 | push 2.0f on the stack | |||
fdiv | divide two floats | |||
fload | load a float value from a local variable #index | |||
fload_0 | load a float value from local variable 0 | |||
fload_1 | load a float value from local variable 1 | |||
fload_2 | load a float value from local variable 2 | |||
fload_3 | load a float value from local variable 3 | |||
fmul | multiply two floats | |||
fneg | negate a float | |||
frem | get the remainder from a division between two floats | |||
freturn | return a float | |||
fstore | store a float value into a local variable #index | |||
fstore_0 | store a float value into local variable 0 | |||
fstore_1 | store a float value into local variable 1 | |||
fstore_2 | store a float value into local variable 2 | |||
fstore_3 | store a float value into local variable 3 | |||
fsub | subtract two floats | |||
getfield | get a field value of an object objectref, where the field is identified by field reference in the constant pool index (indexbyte1 << 8 \ | indexbyte2) | ||
getstatic | get a static field value of a class, where the field is identified by field reference in the constant pool index (indexbyte1 << 8 \ | indexbyte2) | ||
goto | goes to another instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
goto_w | goes to another instruction at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 \ | branchbyte2 << 16 \ | branchbyte3 << 8 \ | branchbyte4) |
i2b | convert an int into a byte | |||
i2c | convert an int into a character | |||
i2d | convert an int into a double | |||
i2f | convert an int into a float | |||
i2l | convert an int into a long | |||
i2s | convert an int into a short | |||
iadd | add two ints | |||
iaload | load an int from an array | |||
iand | perform a bitwise AND on two integers | |||
iastore | store an int into an array | |||
iconst_m1 | load the int value −1 onto the stack | |||
iconst_0 | load the int value 0 onto the stack | |||
iconst_1 | load the int value 1 onto the stack | |||
iconst_2 | load the int value 2 onto the stack | |||
iconst_3 | load the int value 3 onto the stack | |||
iconst_4 | load the int value 4 onto the stack | |||
iconst_5 | load the int value 5 onto the stack | |||
idiv | divide two integers | |||
if_acmpeq | if references are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
if_acmpne | if references are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
if_icmpeq | if ints are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
if_icmpge | if value1 is greater than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
if_icmpgt | if value1 is greater than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
if_icmple | if value1 is less than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
if_icmplt | if value1 is less than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
if_icmpne | if ints are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
ifeq | if value is 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
ifge | if value is greater than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
ifgt | if value is greater than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
ifle | if value is less than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
iflt | if value is less than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
ifne | if value is not 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
ifnonnull | if value is not null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
ifnull | if value is null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 \ | branchbyte2) | ||
iinc | increment local variable #index by signed byte const | |||
iload | load an int value from a local variable #index | |||
iload_0 | load an int value from local variable 0 | |||
iload_1 | load an int value from local variable 1 | |||
iload_2 | load an int value from local variable 2 | |||
iload_3 | load an int value from local variable 3 | |||
impdep1 | reserved for implementation-dependent operations within debuggers; should not appear in any class file | |||
impdep2 | reserved for implementation-dependent operations within debuggers; should not appear in any class file | |||
imul | multiply two integers | |||
ineg | negate int | |||
instanceof | determines if an object objectref is of a given type, identified by class reference index in constant pool (indexbyte1 << 8 \ | indexbyte2) | ||
invokedynamic | invokes 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) | ||
invokeinterface | invokes 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) | ||
invokespecial | invoke 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) | ||
invokestatic | invoke 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) | ||
invokevirtual | invoke 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) | ||
ior | bitwise int OR | |||
irem | logical int remainder | |||
ireturn | return an integer from a method | |||
ishl | int shift left | |||
ishr | int arithmetic shift right | |||
istore | store int value into variable #index | |||
istore_0 | store int value into variable 0 | |||
istore_1 | store int value into variable 1 | |||
istore_2 | store int value into variable 2 | |||
istore_3 | store int value into variable 3 | |||
isub | int subtract | |||
iushr | int logical shift right | |||
ixor | int 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 |
l2d | convert a long to a double | |||
l2f | convert a long to a float | |||
l2i | convert a long to a int | |||
ladd | add two longs | |||
laload | load a long from an array | |||
land | bitwise AND of two longs | |||
lastore | store a long to an array | |||
lcmp | push 0 if the two longs are the same, 1 if value1 is greater than value2, -1 otherwise | |||
lconst_0 | push 0L (the number zero with type long) onto the stack | |||
lconst_1 | push 1L (the number one with type long) onto the stack | |||
ldc | push 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_w | push 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_w | push 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) | ||
ldiv | divide two longs | |||
lload | load a long value from a local variable #index | |||
lload_0 | load a long value from a local variable 0 | |||
lload_1 | load a long value from a local variable 1 | |||
lload_2 | load a long value from a local variable 2 | |||
lload_3 | load a long value from a local variable 3 | |||
lmul | multiply two longs | |||
lneg | negate a long | |||
lookupswitch | a target address is looked up from a table using a key and execution continues from the instruction at that address | |||
lor | bitwise OR of two longs | |||
lrem | remainder of division of two longs | |||
lreturn | return a long value | |||
lshl | bitwise shift left of a long value1 by int value2 positions | |||
lshr | bitwise shift right of a long value1 by int value2 positions | |||
lstore | store a long value in a local variable #index | |||
lstore_0 | store a long value in a local variable 0 | |||
lstore_1 | store a long value in a local variable 1 | |||
lstore_2 | store a long value in a local variable 2 | |||
lstore_3 | store a long value in a local variable 3 | |||
lsub | subtract two longs | |||
lushr | bitwise shift right of a long value1 by int value2 positions, unsigned | |||
lxor | bitwise XOR of two longs | |||
monitorenter | enter monitor for object ("grab the lock" – start of synchronized() section) | |||
monitorexit | exit monitor for object ("release the lock" – end of synchronized() section) | |||
multianewarray | create 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.] | ||
new | create new object of type identified by class reference in constant pool index (indexbyte1 << 8 \ | indexbyte2) | ||
newarray | create new array with count elements of primitive type identified by atype | |||
nop | perform no operation | |||
pop | discard the top value on the stack | |||
pop2 | discard the top two values on the stack (or one value, if it is a double or long) | |||
putfield | set field to value in an object objectref, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 \ | indexbyte2) | ||
putstatic | set 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) | |||
return | return void from method | |||
saload | load short from array | |||
sastore | store short to array | |||
sipush | push a short onto the stack as an integer value | |||
swap | swaps two top words on the stack (note that value1 and value2 must not be double or long) | |||
tableswitch | continue execution from an address in the table at offset index | |||
wide | execute 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/
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。