问题背景
安卓开发过程中,经常要通过看一些java代码对应的字节码,来了解java代码编译后的运行机制,本文将通过一个简单的demo介绍一些基本的字节码指令。
问题分析
比如以下代码:
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);
}
}
运行结果如下:
a += b + c <==> a += (b + c),查看对应的字节码文件如下:
// 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
}
问题总结
通过查看java代码对应的字节码,可以比较清楚的看到java代码编译后的执行流程。在安卓开发中,了解字节码知识还是非常有必要的,在关键时刻,我们查看字节码,能够很好的解答一些疑惑,下面是常见的一些字节码指令:
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: 运行时动态解析并绑定方法调用
持续更新,有兴趣的小伙伴可以进一步深入研究。