problem background
In the process of Android development, it is often necessary to understand the operation mechanism of the compiled java code by looking at the bytecode corresponding to the java code. This article will introduce some basic bytecode instructions through a simple demo.
problem analysis
For example the following code:
public class test {
public static void main(String[] args) {
int a = 100;
int b = 100;
int c = 100;
a += b + c;
System.out.println(a);
}
}
The result of the operation is as follows:
a += b + c <==> a += (b + c), check the corresponding bytecode file as follows:
// class version 52.0 (52)
// access flags 0x21
public class test {
// compiled from: test.java
// access flags 0x1
public <init>()V
L0
LINENUMBER 1 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Ltest; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x9
public static main([Ljava/lang/String;)V
L0
LINENUMBER 3 L0
BIPUSH 100
ISTORE 1 // 将100存储到局部变量
L1
LINENUMBER 4 L1
BIPUSH 100
ISTORE 2 // 将100存储到局部变量
L2
LINENUMBER 5 L2
BIPUSH 100
ISTORE 3 // 将100存储到局部变量
L3
LINENUMBER 6 L3
ILOAD 1 // 从局部变量表中加载 int 类型到操作数栈
ILOAD 2 // 从局部变量表中加载 int 类型到操作数栈
ILOAD 3 // 从局部变量表中加载 int 类型到操作数栈
IADD // 将栈顶两个 int 类型数值相加
IADD // 将栈顶两个 int 类型数值相加
ISTORE 1 // 将 int 类型存储到局部变量中,这里就是把结果存储到第一个变量
L4
LINENUMBER 7 L4
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ILOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (I)V
L5
LINENUMBER 8 L5
RETURN
L6
LOCALVARIABLE args [Ljava/lang/String; L0 L6 0
LOCALVARIABLE a I L1 L6 1
LOCALVARIABLE b I L2 L6 2
LOCALVARIABLE c I L3 L6 3
MAXSTACK = 3
MAXLOCALS = 4
}
conclusion of issue
By viewing the bytecode corresponding to the java code, you can clearly see the execution process of the compiled java code. In Android development, it is very necessary to understand bytecode knowledge. At critical moments, we can look at the bytecode to answer some doubts. The following are some common bytecode instructions:
1. 加载和存储指令:
aload:从局部变量表中加载引用类型到操作数栈。
astore:将引用类型存储到局部变量表中。
iload:从局部变量表中加载 int 类型到操作数栈。
istore:将 int 类型存储到局部变量表中。
fload:从局部变量表中加载 float 类型到操作数栈。
fstore:将 float 类型存储到局部变量表中。
2. 算术和逻辑指令:
iadd:将栈顶两个 int 类型数值相加。
isub:将栈顶两个 int 类型数值相减。
imul:将栈顶两个 int 类型数值相乘。
idiv:将栈顶两个 int 类型数值相除。
iand:将栈顶两个 int 类型数值进行按位与操作。
ior:将栈顶两个 int 类型数值进行按位或操作。
3. 类型转换指令:
i2l:将 int 类型转换为 long 类型。
l2i:将 long 类型转换为 int 类型。
f2d:将 float 类型转换为 double 类型。
d2i:将 double 类型转换为 int 类型。
4. 控制流指令:
if_icmpeq:如果两个 int 类型数值相等,则跳转到指定位置。
goto:无条件跳转到指定位置。
tableswitch:根据索引值跳转到不同位置的指令。
5. 方法调用和返回指令:
invokevirtual:调用实例方法。
invokestatic:调用静态方法。
invokeinterface:调用接口方法。
ireturn:从方法中返回 int 类型值。
invokedynamic: 运行时动态解析并绑定方法调用
Continuously updated, interested partners can further in-depth research.