财政局门户网站建设方案个人网站要备案吗
JVM 字节码指令集非常庞大,包含了大量的指令来完成各种操作。 我们只需要掌握一些常用的字节码指令即可。
以下是一些最常用、最核心的 JVM 字节码指令,按照功能类别进行划分:
1. 操作数栈 (Operand Stack) 操作指令:
nop(No Operation): 什么也不做,空指令,通常用于调试或占位。aconst_null(Push null): 将null引用值推送到操作数栈顶。iconst_m1,iconst_0,iconst_1,iconst_2,iconst_3,iconst_4,iconst_5(Push int constant): 将int型常量-1, 0, 1, 2, 3, 4, 5推送到操作数栈顶。fconst_0,fconst_1,fconst_2(Push float constant): 将float型常量0.0f, 1.0f, 2.0f推送到操作数栈顶。dconst_0,dconst_1(Push double constant): 将double型常量0.0d, 1.0d推送到操作数栈顶。lconst_0,lconst_1(Push long constant): 将long型常量0L, 1L推送到操作数栈顶。bipush <b>(Push byte): 将byte型常量<b>推送到操作数栈顶。sipush <s> (Push short): 将short型常量<s> 推送到操作数栈顶。ldc <index>(Load constant): 从常量池中加载int,float,String类型常量或类引用推送到操作数栈顶。ldc_w <index>(Load constant wide): 宽索引版本ldc,用于加载常量池索引范围更大的常量。ldc2_w <index>(Load constant wide 2): 从常量池中加载long或double类型常量推送到操作数栈顶 (占用两个栈槽)。pop(Pop top operand stack value): 将栈顶数值弹出 (通常用于丢弃不需要的计算结果)。pop2(Pop top 2 operand stack values): 将栈顶两个数值弹出 (用于long和double类型,或两个非long和double类型的值)。dup(Duplicate top operand stack value): 复制栈顶数值,并将副本压入栈顶。dup_x1(Duplicate top operand stack value and insert below): 复制栈顶数值,并将副本插入到栈顶数值之下。dup_x2(Duplicate top operand stack value and insert two values down): 复制栈顶数值,并将副本插入到栈顶数值之下两个位置。dup2(Duplicate top 1 or 2 operand stack values): 复制栈顶一个或两个数值,并将副本压入栈顶 (用于long和double或两个非long和double类型的值)。dup2_x1(Duplicate top 1 or 2 operand stack values and insert below): 复制栈顶一个或两个数值,并将副本插入到栈顶数值之下。dup2_x2(Duplicate top 1 or 2 operand stack values and insert two values down): 复制栈顶一个或两个数值,并将副本插入到栈顶数值之下两个位置。swap(Swap top two operand stack values): 交换栈顶两个数值。
2. 局部变量表 (Local Variable Table) 访问指令:
iload <index>,fload <index>,aload <index>,lload <index>,dload <index>(Load from local variable): 将指定索引的int,float,reference,long,double型局部变量加载到操作数栈顶。iload_0,iload_1,iload_2,iload_3(Load int from local variable 0-3): 加载索引为0, 1, 2, 3的int型局部变量到栈顶 (更高效的指令)。fload_0,fload_1,fload_2,fload_3(Load float from local variable 0-3): 加载索引为0, 1, 2, 3的float型局部变量到栈顶。aload_0,aload_1,aload_2,aload_3(Load reference from local variable 0-3): 加载索引为0, 1, 2, 3的reference型局部变量到栈顶 (例如this引用通常在索引 0)。lload_0,lload_1,lload_2,lload_3(Load long from local variable 0-3): 加载索引为0, 1, 2, 3的long型局部变量到栈顶。dload_0,dload_1,dload_2,dload_3(Load double from local variable 0-3): 加载索引为0, 1, 2, 3的double型局部变量到栈顶。istore <index>,fstore <index>,astore <index>,lstore <index>,dstore <index>(Store into local variable): 将栈顶的int,float,reference,long,double型数值存储到指定索引的局部变量。istore_0,istore_1,istore_2,istore_3(Store int into local variable 0-3): 将栈顶int型数值存储到索引为0, 1, 2, 3的局部变量 (更高效的指令)。fstore_0,fstore_1,fstore_2,fstore_3(Store float into local variable 0-3): 将栈顶float型数值存储到索引为0, 1, 2, 3的局部变量。astore_0,astore_1,astore_2,astore_3(Store reference into local variable 0-3): 将栈顶reference型数值存储到索引为0, 1, 2, 3的局部变量。lstore_0,lstore_1,lstore_2,lstore_3(Store long into local variable 0-3): 将栈顶long型数值存储到索引为0, 1, 2, 3的局部变量。dstore_0,dstore_1,dstore_2,dstore_3(Store double into local variable 0-3): 将栈顶double型数值存储到索引为0, 1, 2, 3的局部变量。
3. 运算指令:
- 算术运算:
iadd,fadd,dadd,ladd(加法)isub,fsub,dsub,lsub(减法)imul,fmul,dmul,lmul(乘法)idiv,fdiv,ddiv,ldiv(除法)irem,frem,drem,lrem(求余数)ineg,fneg,dneg,lneg(取反)ishl,lshl(左移)ishr,lshr(算术右移)iushr,lushr(逻辑右移)iand,land(按位与)ior,lor(按位或)ixor,lxor(按位异或)iinc <index> <const>(int 变量自增,局部变量表操作)
- 类型转换:
i2b,i2c,i2s(int 转 byte, char, short)i2l,i2f,i2d(int 转 long, float, double)l2i,l2f,l2d(long 转 int, float, double)f2i,f2l,f2d(float 转 int, long, double)d2i,d2l,d2f(double 转 int, long, float)
- 比较:
lcmp(long 比较)fcmpl,fcmpg(float 比较,l表示 NaN 时结果为 -1,g表示 NaN 时结果为 1)dcmpl,dcmpg(double 比较,l表示 NaN 时结果为 -1,g表示 NaN 时结果为 1)
4. 类型转换和检查指令:
checkcast <class>(Check whether object is of given type): 检查对象是否是指定类型,如果是则继续,否则抛出ClassCastException。instanceof <class>(Determine if object is of given type): 检查对象是否是指定类型的实例,结果 (1或0) 推送到操作数栈顶。
5. 对象操作指令:
new <class>(Create new object): 创建一个对象,但不初始化,只在堆上分配空间,并将未初始化的对象引用推送到操作数栈顶。anewarray <component type>(Create new array of references): 创建一个指定组件类型的引用类型数组,数组长度从操作数栈弹出。newarray <atype>(Create new array of primitive type): 创建一个指定基本类型的基本类型数组,数组长度从操作数栈弹出 (例如int,boolean,char等)。arraylength(Get length of array): 获取数组长度,数组引用从操作数栈弹出,数组长度推送到栈顶。aaload,baload,caload,saload,iaload,laload,faload,daload(Load from array): 从数组中加载元素,数组引用和索引从操作数栈弹出,加载的元素值推送到栈顶 (对应reference,byte,char,short,int,long,float,double类型)。aastore,bastore,castore,sastore,iastore,lastore,fastore,dastore(Store into array): 将值存储到数组中,数组引用、索引和要存储的值从操作数栈弹出 (对应reference,byte,char,short,int,long,float,double类型)。getfield <field>(Fetch field from object): 获取对象的实例字段的值,对象引用从操作数栈弹出,字段值推送到栈顶。putfield <field>(Set field in object): 设置对象的实例字段的值,对象引用和要设置的字段值从操作数栈弹出。getstatic <field>(Get static field from class): 获取类的静态字段的值,字段值推送到操作数栈顶。putstatic <field>(Set static field in class): 设置类的静态字段的值,要设置的字段值从操作数栈弹出。
6. 方法调用和返回指令:
invokevirtual <method>(Invoke virtual method): 调用对象的虚方法 (运行时多态)。invokespecial <method>(Invoke instance method; special handling): 调用实例方法,但需要特殊处理的情况,例如:- 调用父类方法 (
super.method()) - 调用私有方法
- 调用构造器 (
<init>)
- 调用父类方法 (
invokestatic <method>(Invoke a class (static) method): 调用静态方法。invokeinterface <interface method>(Invoke interface method): 调用接口方法。invokedynamic <method>(Invoke dynamic method): 用于支持动态语言特性,例如 Lambda 表达式、动态代理等 (JDK 7 新增)。ireturn,freturn,areturn,lreturn,dreturn(Return from method): 从方法返回,并将栈顶的int,float,reference,long,double类型值作为返回值返回。return(Return void from method): 从void方法返回。
7. 控制流指令:
- 条件跳转:
ifeq <branchoffset>(If int compare with zero is equal branch): 如果栈顶int型数值等于 0,则跳转。ifne <branchoffset>(If int compare with zero is not equal branch): 如果栈顶int型数值不等于 0,则跳转。iflt <branchoffset>(If int compare with zero is less than branch): 如果栈顶int型数值小于 0,则跳转。ifge <branchoffset>(If int compare with zero is greater than or equal branch): 如果栈顶int型数值大于等于 0,则跳转。ifgt <branchoffset>(If int compare with zero is greater than branch): 如果栈顶int型数值大于 0,则跳转。ifle <branchoffset>(If int compare with zero is less than or equal branch): 如果栈顶int型数值小于等于 0,则跳转。if_icmpeq <branchoffset>(If int compare equal branch): 如果栈顶两个int型数值相等,则跳转。if_icmpne <branchoffset>(If int compare not equal branch): 如果栈顶两个int型数值不相等,则跳转。if_icmplt <branchoffset>(If int compare less than branch): 如果栈顶第一个int型数值小于第二个,则跳转。if_icmpge <branchoffset>(If int compare greater than or equal branch): 如果栈顶第一个int型数值大于等于第二个,则跳转。if_icmpgt <branchoffset>(If int compare greater than branch): 如果栈顶第一个int型数值大于第二个,则跳转。if_icmple <branchoffset>(If int compare less than or equal branch): 如果栈顶第一个int型数值小于等于第二个,则跳转。ifnull <branchoffset>(If reference is null branch): 如果栈顶reference型数值为null,则跳转。ifnonnull <branchoffset>(If reference is not null branch): 如果栈顶reference型数值不为null,则跳转。
- 无条件跳转:
goto <branchoffset>(Branch always): 无条件跳转到指定偏移量。goto_w <branchoffset>(Branch always wide): 宽偏移量版本goto,用于跳转范围更大的情况。
tableswitch(Access jump table by index and jump): 用于switch语句 (当case值连续时)。lookupswitch(Access jump table by key match and jump): 用于switch语句 (当case值不连续时)。
8. 异常处理指令:
athrow(Throw exception or error): 将栈顶的异常对象抛出。checkcast <class>(Check whether object is of given type): 检查对象类型,如果类型不匹配,抛出ClassCastException(也可以用于类型检查,不仅仅是异常处理)。monitorenter(Enter monitor for object): 尝试获取对象的 monitor (锁),用于synchronized关键字的同步块的开始。monitorexit(Exit monitor for object): 释放对象的 monitor (锁),用于synchronized关键字的同步块的结束。
类型缩写:
在指令助记符中,通常会使用一些类型缩写来表示操作的数据类型:
i: intl: longf: floatd: doublea: reference (对象引用)b: bytec: chars: short
学习建议:
- 无需记住所有指令: 字节码指令数量庞大,不需要全部记住,重点掌握常用的指令和它们的功能。
- 结合实例学习: 通过查看 Java 代码编译后的字节码,结合具体的代码示例来学习指令,更容易理解。可以使用
javap -c <类名>命令反编译.class文件查看字节码。 - 关注指令类别: 按照功能类别 (操作数栈、局部变量表、运算、控制流等) 来学习,更容易形成体系。
- 查阅 JVM 规范: 如果需要深入了解某个指令的细节,可以查阅 JVM 规范 (The Java Virtual Machine Specification)。
- 理解 JVM 的基本执行模型: 基于栈的指令集、操作数栈、局部变量表等。
- 分析 Java 代码的性能: 通过分析字节码,可以了解代码的执行效率,找出潜在的性能瓶颈。
- 进行更深层次的 Java 调优: 理解字节码优化,可以编写更高效的 Java 代码。
- 深入理解 Java 语言特性: 例如,多态、异常处理、同步机制等在字节码层面的实现。
