javap -c命令关键字的含义
jdk提供了javap命令用于查看字节码来查看程序执行赋值的顺序,看懂这些关键字可以很好的理解程序执行的过程
转自:http://www.cnblogs.com/duanxz/archive/2014/05/14/3724426.html#top
Java栈和局部变量操作
Java虚拟机是基于栈的机器,几乎所有Java虚拟机的指令都与操作数栈相关。栈操作包括把常量压入操作数栈、执行通用的栈操作、在操作数栈和局部变量之间往返传输值。
1常量入栈操作:
操作码在执行常量入栈操作之前,使用三种方式指明常量的值:常量值隐含包含在操作码内部、常量值在字节码中如同操作数一样跟随在操作码之后,或者从常量池中取出常量。
1.1常量值隐含包含在操作码内部:
将一个字长的常量压入栈
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
iconst_m1 |
(无) |
将int类型值-1压入栈 |
|
iconst_0 |
(无) |
将int类型值0压入栈 |
|
iconst_1 |
(无) |
将int类型值1压入栈 |
|
iconst_2 |
(无) |
将int类型值2压入栈 |
|
iconst_3 |
(无) |
将int类型值3压入栈 |
|
iconst_4 |
(无) |
将int类型值4压入栈 |
|
iconst_5 |
(无) |
将int类型值5压入栈 |
|
fconst_0 |
(无) |
将float类型值0压入栈 |
|
fconst_1 |
(无) |
将float类型值1压入栈 |
|
fconst_2 |
(无) |
将float类型值2压入栈 |
将两个字长的常量压入栈
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
lconst_0 |
(无) |
将long类型值0压入栈 |
|
lconst_1 |
(无) |
将long类型值1压入栈 |
|
dconst_0 |
(无) |
将double类型值0压入栈 |
|
dconst_1 |
(无) |
将double类型值1压入栈 |
给一个对象引用赋空值时会用到aconst_null指令
将空(null)对象引用压入栈
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
aconst_null |
(无) |
将空(null)对象引用压入栈 |
例如下面代码:
public class StackTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int i = 0;
int j = 4;
int k;
k = i + j;
float a = 0;
float b = 1;
float c = a + b;
long x = 0;
long y = 1;
long z = x + y;
String string = null;
}
}
用javap工具查看其字节码为:
Compiled from "StackTest.java"
public class StackTest extends java.lang.Object{
public StackTest();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_0 //常量int类型的0入栈
1: istore_1 //弹出栈顶元素0存入位置1的局部变量中
2: iconst_4 //常量int类型的4入栈
3: istore_2 //弹出栈顶元素4存入位置2的局部变量中
4: iload_1 //从位置为1的局部变量中取出元素int类型的0压入栈
5: iload_2 //从位置为2的局部变量中取出元素int类型的4压入栈
6: iadd //从栈顶弹出两个元素然后做加法,把结果压入栈
7: istore_3 //弹出栈顶元素4存入位置为3的局部变量中
8: fconst_0 //常量float类型的0入栈
9: fstore 4 //弹出栈顶元素0存入位置为4的局部变量中
11: fconst_1 //常量float类型的1入栈
12: fstore 5 //弹出栈顶元素1存入位置为5的局部变量中
14: fload 4 //从位置为4的局部变量中取出元素float类型的0压入栈
16: fload 5 //从位置为5的局部变量中取出元素float类型的1压入栈
18: fadd //从栈顶弹出两个元素然后做加法,把结果压入栈
19: fstore 6 //弹出栈顶元素1存入位置为3的局部变量中
21: lconst_0 //常量long类型的0入栈
22: lstore 7 // 弹出栈顶元素0存入位置为7和8的局部变量中
24: lconst_1 //常量long类型的1入栈
25: lstore 9 // 弹出栈顶元素0存入位置为9和10的局部变量中
27: lload 7 //从位置为7和8的局部变量中取出元素long类型的0压入栈
29: lload 9 //从位置为9和10的局部变量中取出元素long类型的1压入栈
31: ladd //从栈顶弹出两个元素然后做加法,把结果压入栈
32: lstore 11 //弹出栈顶元素1存入位置为11和12的局部变量中
34: aconst_null //将null对象引用压入栈
35: astore 13 //弹出栈顶元素null存入位置为13的局部变量中
37: return
}
1.2常量值在字节码中跟随在操作码之后:
将byte和short类型常量压入栈
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
bipush |
一个byte类型的数 |
将byte类型的数转换为int类型的数,然后压入栈 |
|
sipush |
一个short类型的数 |
将short类型的数转换为int类型的数,然后压入栈 |
1.3从常量池中取出常量
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
ldc |
无符号8位数indexbyte |
从由indexbyte指向的常量池入口中取出一个字长的值,然后将其压入栈 |
|
ldc_w |
无符号16位数indexshort |
从由indexshort指向的常量池入口中取出一个字长的值,然后将其压入栈 |
|
ldc2_w |
无符号16位数indexshort |
从由indexshort指向的常量池入口中取出两个字长的值,然后将其压入栈 |
这三个操作码是从常量池中取出常量,然后将其压入栈,这些操作码的操作码表示常量池索引,Java虚拟机通过给定的索引查找相应的常量池入口,决定这些常量的类型和值,并把它们压入栈。
常量池索引是一个无符号值,ldc和ldc_w是把一个字长的项压入栈,区别在于:ldc的索引只有一个8位,只能指向常量池中1~255范围的位置。ldc_w的索引有16位,可以指向1~65535范围的位置。
例如下面代码:
public class StackTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
byte i = 125;
byte j = -128;
int k = i + j;
short a = 32767;
short b = - 32768;
int c = a + b;
int x = 2147483647;
int y = -2147483648;
int z = x + y;
long I = 2147483648L;
long J = -2147483649L;
long K = I + J;
}
}
用javap工具查看其字节码为:
Compiled from "StackTest.java"
public class StackTest extends java.lang.Object{
public StackTest();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: bipush 125 //将byte类型的255转换成int类型压入栈
2: istore_1 //弹出栈顶元素255存入位置为1的局部变量中
3: bipush -128 //将byte类型的-128转换成int类型压入栈
5: istore_2 //弹出栈顶元素-128存入位置为2的局部变量中
6: iload_1 //取出位置为1的局部变量中的数压入栈
7: iload_2 //取出位置为2的局部变量中的数压入栈
8: iadd //从栈顶弹出两个元素然后做加法,把结果压入栈
9: istore_3 //弹出栈顶元素存入位置为3的局部变量中
10: sipush 32767 //将short类型的32767转换成int类型压入栈
13: istore 4 //弹出栈顶元素32767存入位置为4的局部变量中
15: sipush -32768 /将short类型的-32768转换成int类型压入栈
18: istore 5 //弹出栈顶元素-32768存入位置为5的局部变量中
20: iload 4 //取出位置为4的局部变量中的数压入栈
22: iload 5 //取出位置为5的局部变量中的数压入栈
24: iadd //从栈顶弹出两个元素然后做加法,把结果压入栈
25: istore 6 /弹出栈顶元素存入位置为6的局部变量中
27: ldc #16; //int 2147483647 //从常量池索引16的位置取出2147483647压入栈
29: istore 7 //弹出栈顶元素2147483647存入位置为4的局部变量中
31: ldc #17; //int -2147483648 //从常量池索引17的位置取出-2147483648压入栈
33: istore 8 //弹出栈顶元素-2147483648存入位置为8的局部变量中
35: iload 7 //取出位置为7的局部变量中的数压入栈
37: iload 8 //取出位置为8的局部变量中的数压入栈
39: iadd //从栈顶弹出两个元素然后做加法,把结果压入栈
40: istore 9 //弹出栈顶元素存入位置为9的局部变量中
42: ldc2_w #18; //long 2147483648l //从常量池索引18的位置取出long类型的2147483648L压入栈
45: lstore 10 //弹出栈顶元素2147483648L存入位置为10和11的局部变量中
47: ldc2_w #20; //long -2147483649l //从常量池索引20的位置取出long类型的-2147483649L压入栈
50: lstore 12 //弹出栈顶元素-2147483649L存入位置为12和13的局部变量中
52: lload 10 //取出位置为10和11的局部变量中的数压入栈
54: lload 12 //取出位置为12和13的局部变量中的数压入栈
56: ladd //从栈顶弹出两个元素然后做加法,把结果压入栈
57: lstore 14 //弹出栈顶元素存入位置为14和15的局部变量中
59: return
}
2通用栈操作
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
nop |
(无) |
不做任何操作 |
|
pop |
(无) |
从操作数栈弹出栈顶部的一个字 |
|
pop2 |
(无) |
从操作数栈弹出最顶端的两个字 |
|
swap |
(无) |
交换栈顶部的两个字 |
|
dup |
(无) |
复制栈顶部的一个字 |
|
dup2 |
(无) |
复制栈顶部的两个字 |
|
dup_x1 |
(无) |
复制栈顶部的一个字,并将复制内容及原来弹出的两个字长的内容压入栈 |
|
dup_x2 |
(无) |
复制栈顶部的一个字,并将复制内容及原来弹出的三个字长的内容压入栈 |
|
dup2_x1 |
(无) |
复制栈顶部的两个字,并将复制内容及原来弹出的三个字长的内容压入栈 |
|
dup2_x2 |
(无) |
复制栈顶部的两个字,并将复制内容及原来弹出的四个字长的内容压入栈 |
1,dup:复制栈顶部的一个字长的内容。
栈:
前:......,word
后:......,word,word
2,dup_x1:复制栈顶部一个字长的内容,然后将复制内容及原来弹出的两个字长的内容压入栈
栈:
前:......,word2,word1
后:......,word1,word2,word1
3,dup_x2:复制栈顶部一个字长的内容,然后将复制内容及原来弹出的三个字长的内容压入栈
栈:
前:.......,word3,word2,word1
后:.......,word1,word3,word2,word1
4,dup2:复制栈顶部长度为两个字长的内容
栈:
前:......,word2,word1
后:......,word2,word1,word2,word1
5,dup2_x1:复制栈顶部两个字长的内容,然后将复制内容及原来弹出的三个字长的内容压入栈
栈:
前:......,word3,word2,word1
后:.......,word2,word1,word3,word2,word1
6,dup2_x2:复制栈顶部两个字长的内容,然后将复制内容及原来弹出的四个字长的内容压入栈
栈:
前:......,word4,word3,word2,word1
后:.......,word2,word1,word4,word3,word2,word1
7,pop:弹出栈顶端一个字长的内容
栈:
前:......,word
后:.......
8,pop2:弹出栈顶端两个字长的内容
栈:
前:......,word2,word1
后:.......
9,swap:交换栈顶端两个字的内容
栈:
前:......,word2,word1
后:.......,word1,word2
例如如下代码:
public class StackTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String a;
String b;
a = new String("aaa");
b = new String("aaa");
}
}
用javap工具查看其字节码为:
Compiled from "StackTest.java"
public class StackTest extends java.lang.Object{
public StackTest();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #16; //class java/lang/String
3: dup
4: ldc #18; //String aaa
6: invokespecial #20; //Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: new #16; //class java/lang/String
13: dup
14: ldc #18; //String aaa
16: invokespecial #20; //Method java/lang/String."<init>":(Ljava/lang/String;)V
19: astore_2
20: return
}
3,把局部变量压入栈
将一个字长的局部变量压入栈
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
iload |
vindex |
将位置为vindex的int类型的局部变量压入栈 |
|
iload_0 |
(无) |
将位置为0的int类型的局部变量压入栈 |
|
iload_1 |
(无) |
将位置为1的int类型的局部变量压入栈 |
|
iload_2 |
(无) |
将位置为2的int类型的局部变量压入栈 |
|
iload_3 |
(无) |
将位置为3的int类型的局部变量压入栈 |
|
fload |
vindex |
将位置为vindex的float类型的局部变量压入栈 |
|
fload_0 |
(无) |
将位置为0的float类型的局部变量压入栈 |
|
fload_1 |
(无) |
将位置为1的float类型的局部变量压入栈 |
|
fload_2 |
(无) |
将位置为2的float类型的局部变量压入栈 |
|
fload_3 |
(无) |
将位置为3的float类型的局部变量压入栈 |
将两个字长的局部变量压入栈
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
lload |
vindex |
将位置为vindex和(vindex+1)的long类型的局部变量压入栈 |
|
lload_0 |
(无) |
将位置为0和1的long类型的局部变量压入栈 |
|
lload_1 |
(无) |
将位置为1和2的long类型的局部变量压入栈 |
|
lload_2 |
(无) |
将位置为2和3的long类型的局部变量压入栈 |
|
lload_3 |
(无) |
将位置为3和4的long类型的局部变量压入栈 |
|
dload |
vindex |
将位置为vindex和(vindex+1)的double类型的局部变量压入栈 |
|
dload_0 |
(无) |
将位置为0和1的double类型的局部变量压入栈 |
|
dload_1 |
(无) |
将位置为1和2的double类型的局部变量压入栈 |
|
dload_2 |
(无) |
将位置为2和3double类型的局部变量压入栈 |
|
dload_3 |
(无) |
将位置为3和4double类型的局部变量压入栈 |
将对象引用局部变量压入栈
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
aload |
vindex |
将位置为vindex的对象引用局部变量压入栈 |
|
aload_0 |
(无) |
将位置为0的对象引用局部变量压入栈 |
|
aload_1 |
(无) |
将位置为1的对象引用局部变量压入栈 |
|
aload_2 |
(无) |
将位置为2的对象引用局部变量压入栈 |
|
aload_3 |
(无) |
将位置为3的对象引用局部变量压入栈 |
4,弹出栈顶元素,将其赋给局部变量
弹出一个字长的值,将其赋给局部变量
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
istore |
vindex |
从栈中弹出int类型值,然后将其存到位置为vindex的局部变量中 |
|
istore_0 |
(无) |
从栈中弹出int类型值,然后将其存到位置为0的局部变量中 |
|
istore_1 |
(无) |
从栈中弹出int类型值,然后将其存到位置为1的局部变量中 |
|
istore_2 |
(无) |
从栈中弹出int类型值,然后将其存到位置为2的局部变量中 |
|
istore_3 |
(无) |
从栈中弹出int类型值,然后将其存到位置为3的局部变量中 |
|
fstore |
vindex |
从栈中弹出float类型值,然后将其存到位置为vindex的局部变量中 |
|
fstore_0 |
(无) |
从栈中弹出float类型值,然后将其存到位置为0的局部变量中 |
|
fstore_1 |
(无) |
从栈中弹出float类型值,然后将其存到位置为1的局部变量中 |
|
fstore_2 |
(无) |
从栈中弹出float类型值,然后将其存到位置为2的局部变量中 |
|
fstore_3 |
(无) |
从栈中弹出float类型值,然后将其存到位置为3的局部变量中 |
弹出对象引用,并将其赋值给局部变量
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
lstore |
vindex |
从栈中弹出long类型值,然后将其存到位置为vindex和(vindex+1)的局部变量中 |
|
lstore_0 |
(无) |
从栈中弹出long类型值,然后将其存到位置为0和1的局部变量中 |
|
lstore_1 |
(无) |
从栈中弹出long类型值,然后将其存到位置为1和2的局部变量中 |
|
lstore_2 |
(无) |
从栈中弹出long类型值,然后将其存到位置为2和3的局部变量中 |
|
lstore_3 |
(无) |
从栈中弹出long类型值,然后将其存到位置为3和4的局部变量中 |
|
dstore |
vindex |
从栈中弹出double类型值,然后将其存到位置为vindex和(vindex+1)的局部变量中 |
|
dstore_0 |
(无) |
从栈中弹出double类型值,然后将其存到位置为0和1的局部变量中 |
|
dstore_1 |
(无) |
从栈中弹出double类型值,然后将其存到位置为1和2的局部变量中 |
|
dstore_2 |
(无) |
从栈中弹出double类型值,然后将其存到位置为2和3的局部变量中 |
|
dstore_3 |
(无) |
从栈中弹出double类型值,然后将其存到位置为3和4的局部变量中 |
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
astore |
vindex |
从栈中弹出对象引用,然后将其存到位置为vindex的局部变量中 |
|
astore_0 |
(无) |
从栈中弹出对象引用,然后将其存到位置为0的局部变量中 |
|
astore_1 |
(无) |
从栈中弹出对象引用,然后将其存到位置为1的局部变量中 |
|
astore_2 |
(无) |
从栈中弹出对象引用,然后将其存到位置为2的局部变量中 |
|
astore_3 |
(无) |
从栈中弹出对象引用,然后将其存到位置为3的局部变量中 |
5,wide指令
无符号8位局部变量索引,把方法中局部变量数的限制在256以下。一条单独的wide指令可以将8位的索引再扩展8位,就可以把局部变量数的限制扩展到65536.
|
操作码 |
操作数 |
说明 |
|---|---|---|
|
wide |
iload,index |
从局部变量位置为index的地方取出int类型值,并将其压入栈 |
|
wide |
lload ,index |
从局部变量位置为index的地方取出long类型值,并将其压入栈 |
|
wide |
fload,index |
从局部变量位置为index的地方取出float类型值,并将其压入栈 |
|
wide |
dload,index |
从局部变量位置为index的地方取出double类型值,并将其压入栈 |
|
wide |
aload,index |
从局部变量位置为index的地方取出对象引用,并将其压入栈 |
|
wide |
istore,index |
从栈中弹出int类型值,将其存入位置为index的局部变量中 |
|
wide |
lstore,index |
从栈中弹出long类型值,将其存入位置为index的局部变量中 |
|
wide |
fstore,index |
从栈中弹出float类型值,将其存入位置为index的局部变量中 |
|
wide |
dstore,index |
从栈中弹出double类型值,将其存入位置为index的局部变量中 |
|
wide |
astore,index |
从栈中弹出对象引用,将其存入位置为index的局部变量中 |
跳转指令并不允许直接跳转到被wide指令修改过的操作码。
javap -c命令关键字的含义的更多相关文章
- iOS中assign、copy 、retain等关键字的含义
iOS中assign.copy .retain等关键字的含义 转自:http://my.oschina.net/majiage/blog/267409 assign: 简单赋值,不更改索引计数cop ...
- 【转】java中volatile关键字的含义
java中volatile关键字的含义 在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言 ...
- Linux Free命令各数字含义及Buffer和Cache的区别
Linux Free命令各数字含义及Buffer和Cache的区别 Free 命令的各数字含义 命令演示 [root@vm1 ~]# free total used free shared buffe ...
- 转:java中volatile关键字的含义
转:java中volatile关键字的含义 在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言 ...
- iOS-assign、copy 、retain等关键字的含义
iOS中assign.copy .retain等关键字的含义 assign: 简单赋值,不更改索引计数 copy: 建立一个索引计数为1的对象,然后释放旧对象 retain:释放旧的对象,将旧对象的值 ...
- 【转】javap -c命令详解
javap -c命令详解 一直在学习Java,碰到了很多问题,碰到了很多关于i++和++i的难题,以及最经典的String str = "abc" 共创建了几个对象的疑难杂症. 知 ...
- Linux manual中命令标号的含义
如果查看Linux manual(例如,执行:man open), 会发现文档中有这样的表达方式:read(2), write(2), lseek(2), fcntl(2)等,括号中的数值表达什么含义 ...
- Linux chmod命令及权限含义
对于一条权限赋值命令:sudo chmod -R 764 ×××:我们必须了解其含义: (1)各字段含义:sudo chmod -R(更改文件夹及其子文件夹) ...
- 【Java】Java关键字、含义
Java关键字 来自 Java 核心技术卷I 基础知识(原书第10 版)/( 美)凯S 霍斯特曼(Cay S . Horstmann )著: 周立新等译一北京:机械工业出版社, 2016 . 8 Ja ...
随机推荐
- Android内核解读-应用的安装过程
前言 我们知道,在android手机上安装一个apk很简单,只要打开apk文件,默认就会弹出安装界面,然后点击确定,经过若干秒后,apk就安装成功了,可是你知道apk的安装过程是什么吗?你知道andr ...
- BT656跟BT1120和BT709有什么区别
601是SDTV的数据结构 656是SDTV的interface709是HDTV的数据结构 1120是HDTV的interface从数据结构上 都是Y Cb Cr只是SDTV用4:2:2 HDTV ...
- javascript 获取随机数
javascript 获取随机数 var rand=Math.floor(Math.random()*(n+1)) floor 向下取整 random 获得0-1之间的随机数
- 使用jsoup抓取新闻信息
1,jsoup简介 jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址.HTML文本内容.它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和 ...
- linux下mount/unmount命令
格式:mount [-参数] [设备名称] [挂载点] 其中常用的参数有:-a 安装在/etc/fstab文件中类出的所有文件系统.-f 伪装mount,作出检查设备和目录的样子,但并不真正挂载文件系 ...
- Html细线表格的实现 打印边框设置
在网页制作中,我们常常会使用到表格,表格使得需要表达的信息更清楚,明了. <table border="1" cellspacing="0" border ...
- 为你揭露2018微信公开课pro的12个重点
为你揭露2018微信公开课pro的12个重点 1月15日,微信公开课Pro版现场,微信又为我们带来了一些重磅消息,小程序依旧是本次微信公开课Pro的绝对重点.小编为大家整理了公开课的12个重点,带大家 ...
- 编写第一个Flutter App(翻译)
博客搬迁至http://blog.wangjiegulu.com RSS订阅:http://blog.wangjiegulu.com/feed.xml 以下代码 Github 地址:https://g ...
- Maven 搭建 SSM 项目 (oracle)
简单谈一下maven搭建 ssm 项目 (使用数据库oracle,比 mysql 难,所以这里谈一下) 在创建maven 的web项目时,常常会缺了main/java , main/test 两个文件 ...
- 一个VB编写的俄罗斯方块
'VB语言版俄罗斯方块'Totoo.Aoo34智造(一个人的两个名字),一些方块,很多计算 Const WN As Integer = 10, HN As Integer = 20Const Boxl ...