字节码指令
java 虚拟机的指令由一个字节长度的,代表着某种特定操作的含义的数字,称为操作码,以及跟随其后零至多个代表此操作所需参数的操作数而组成
操作码的长度为1个字节,因此最大只有256条
基于栈的指令集架构.
在虚拟机的指令集中,大多数的指令都包含了其操作所对应的数据类型信息
lload fload
也有不包含类型信息的
Goto与类型无关
Arraylength操作数组类型
加载与存储指令
加载和存储指令用于将数据在栈帧中的局部变量表和操作数栈之间来回传输
将局部变量表加载到操作数栈:iload lload fload dload aload
将一个数值从操作数栈存储到局部变量表:istore lfda
将一个常量加载代操作数栈:bipush sipush ldc_w ldc2_w aconst_null iconst_m1 iconst
扩充局部变量表的访问索引的指令 : wide
public class HelloWorld { public int add(int a,int b){ return a + b; } }
iload_1 iload_2 进栈
iadd iload_ 1和 iload_2相加
istore_3 将a+b的和存在局部变量表
iconst_2 常量为2 1+1 编译器优化,直接相加
运算指令
运算和算术指令用于对于对两个操作数栈上的值进行某种特定的运算,
并把结果存储到操作数栈顶
加 add i l f d 栈顶的两个元素相加,不是栈所由元素相加
减 sub
乘 mul
除 div
取余 rem
取反 neg
1 public class HelloWorld { 2 public int add(int a ,int b){ 3 int c = a + b; 4 int d = a - b; 5 int e = a * b; 6 int f = a / b; 7 int g = a % b; 8 return 1 + 1; 9 } 10 }
iadd 计算完存在栈中,istore 从栈中移到局部变量表中.
类型转换指令
类型转换指令可以将两种不同的类型进行相互转换,这些转换一般用于实现用户代码中的
显示类型转换操作以及用来处理字节码指令集中数据类型相关指令无法与数据类型一一对应问题
宽化类型处理和窄化类型处理
int i = 10;
Long a = i;
1 public class HelloWorld { 2 3 public static int add(int a ,int b){ 4 5 int hour = 24; 6 long mi = hour * 60 * 60 * 1000; 7 long mic = hour * 60 * 60 * 1000 * 1000; 8 9 System.out.print(mic/mi); 10 11 return 1 + 1; 12 } 13 14 public static void main (String [] args){ 15 add(1,2); 16 } 17 18 }
将24加入操作数栈中,加到局部变量表中,再次加到栈中,
将60加入到操作数栈中,imul执行乘法运算。前者都执行i 类型的,后 i2l ,将int 类型转换成 long 类型 ,i发生越界。
并不是前者定义一个 long 类型, 后都根据 long 类型进行运算。
对象创建与访问指令
创建类实例指令:new
创建数组指令:newarray anewarray multianwarray
创建类字段:getfield putfield getstatic putstatic
把数组元素加载到操作数栈的指令:astore
取数组长度的指令 arraylength
检查实例类型的指令: instanceof checkcast
1 public class HelloWorld { 2 3 4 public static void main(String [] args){ 5 User user = new User(); 6 User[] us = new User[10]; 7 int[] as = new int(10); 8 9 user.name = "hello"; 10 String name = user.name; 11 12 } 13 14 } 15 16 class User { 17 String name; 18 static int age; 19 20 }
操作栈管理指令
操作数栈指令用于直接操作操作数栈
将操作数栈的一个或两个元素出栈 pop pop2
复制栈顶一个或两个数值并将复制或双份复制值重新压入栈顶
dup dup2 dup_x1 dup_x2
将栈顶的两个数值替换
控制转移指令
控制转移指令可以让Java虚拟机有条件或无条件的从指定的位置指令而不是控制转移指令的
下一条指令继续执行程序。可以认为控制转移指令就是在修改pc寄存器的值。
条件分支 : ifeq ifle iflt ifne ifgt ifnull ifcmple
复合条件分支:tableswitch lookupswitch
无条件分支: goto goto_w jsr jsr_w ret
1 public class HelloWorld { 2 3 4 public static void main(String [] args){ 5 int a = 10; 6 7 if(a > 10){ 8 System.out.println(">10"); 9 }else{ 10 System.out.println("<=10"); 11 } 12 13 } 14 15 }
bipush 10 放到操作数栈中
iload 1 将a加载到操作数栈中
if_icmple 将操作数栈中两个值进行比较,不成功,跳转到20行
getstatic 获取out,获取标准的输出流
ldc 加载常量到操作数栈中
方法调用指令
invokevirtual 指令用于调用对象的实例方法,根据对象的实际类型进行分派方式
invokeinterface指令用于调用接口方法,他会在运行时搜索一个实现了这个接口方法的对象,找出适合的方法调用
invokespecial指令用于调用一些需要特殊处理的实例方法,包括实例初始化方法,私有方法和父类方法
invokestatic 指令用于调用类的方法(static)
1 public class HelloWorld { 2 3 4 public static void main(String [] args){ 5 6 Service s = new ServiceImpl(); 7 int res = s.add(1,2); 8 9 } 10 11 } 12 13 interface Service { 14 int add (int a,int b); 15 } 16 17 class ServiceImpl implements Service { 18 public int add(int a,int b){ 19 return a + b; 20 } 21 }
方法的调用指令与数据类型无关,而方法的返回指令则是根据返回值的类型区分的,包括ireturn(当返回值是boolean,byte,char,short和int类型使用) ,lreturn,freturn,dreturn和areturn,另外一条return指令供声明为void的方法,实例化方法,类和接口的类初始化方法调用.
异常处理指令
在程序中显示抛出异常的操作会由athrow指令实现,除了这种情况,还有别的异常会在其他java虚拟机指令检测到异常状况时由虚拟机自动抛出
1 public class HelloWorld { 2 3 4 public static void main(String [] args){ 5 6 Service s = new ServiceImpl(); 7 int res = s.add(1,2); 8 9 throw new RuntimeException("exception...."); 10 11 } 12 13 } 14 15 interface Service { 16 int add (int a,int b); 17 } 18 19 class ServiceImpl implements Service { 20 public int add(int a,int b){ 21 return a + b; 22 } 23 }
同步指令
java虚拟机可以支持方法级的同步和方法内部一段指令序列的同步,这两种同步结构都是
使用管程(Monitor)来支持的
方法级的同步是隐式,即无需通过字节码指令来控制的,它实现在方法的调用和返回操作之间
在方法执行期间,执行线程持有了管程,其他任何线程都无法获取同一个管程。
同步一段指令集序列通常由Java语言中的synchronized块来表示,java虚拟机中的monitorenter和
monitorexit两条指令来支持synchronized关键字的语义
完
原文:https://www.cnblogs.com/quyangyang/p/11099324.html