zoukankan      html  css  js  c++  java
  • 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存入位置为78的局部变量中

    24: lconst_1 //常量long类型的1入栈

    25: lstore 9 // 弹出栈顶元素0存入位置为910的局部变量中

    27: lload 7 //从位置为78的局部变量中取出元素long类型的0压入栈

    29: lload 9 //从位置为910的局部变量中取出元素long类型的1压入栈

    31: ladd //从栈顶弹出两个元素然后做加法,把结果压入栈

    32: lstore 11 //弹出栈顶元素1存入位置为1112的局部变量中

    34: aconst_null //null对象引用压入栈

    35: astore 13 //弹出栈顶元素null存入位置为13的局部变量中

    37: return

    }

    1.2常量值在字节码中跟随在操作码之后:

    byteshort类型常量压入栈

    操作码

    操作数

    说明

    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虚拟机通过给定的索引查找相应的常量池入口,决定这些常量的类型和值,并把它们压入栈。

    常量池索引是一个无符号值,ldcldc_w是把一个字长的项压入栈,区别在于:ldc的索引只有一个8位,只能指向常量池中1255范围的位置。ldc_w的索引有16位,可以指向165535范围的位置。

    例如下面代码:

    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存入位置为1011的局部变量中

    47: ldc2_w #20; //long -2147483649l //从常量池索引20的位置取出long类型的-2147483649L压入栈

    50: lstore 12 //弹出栈顶元素-2147483649L存入位置为1213的局部变量中

    52: lload 10 //取出位置为1011的局部变量中的数压入栈

    54: lload 12 //取出位置为1213的局部变量中的数压入栈

    56: ladd //从栈顶弹出两个元素然后做加法,把结果压入栈

    57: lstore 14 //弹出栈顶元素存入位置为1415的局部变量中

    59: return

    2通用栈操作

    操作码

    操作数

    说明

    nop

    (无)

    不做任何操作

    pop

    (无)

    从操作数栈弹出栈顶部的一个字

    pop2

    (无)

    从操作数栈弹出最顶端的两个字

    swap

    (无)

    交换栈顶部的两个字

    dup

    (无)

    复制栈顶部的一个字

    dup2

    (无)

    复制栈顶部的两个字

    dup_x1

    (无)

    复制栈顶部的一个字,并将复制内容及原来弹出的两个字长的内容压入栈

    dup_x2

    (无)

    复制栈顶部的一个字,并将复制内容及原来弹出的三个字长的内容压入栈

    dup2_x1

    (无)

    复制栈顶部的两个字,并将复制内容及原来弹出的三个字长的内容压入栈

    dup2_x2

    (无)

    复制栈顶部的两个字,并将复制内容及原来弹出的四个字长的内容压入栈

    1dup:复制栈顶部的一个字长的内容。

    栈:

    前:......,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

    后:.......

    8pop2:弹出栈顶端两个字长的内容

    :

    前:......,word2,word1

    后:.......

    9swap:交换栈顶端两个字的内容

    :

    前:......,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

    将位置为vindexint类型的局部变量压入栈

    iload_0

    ()

    将位置为0int类型的局部变量压入栈

    iload_1

    ()

    将位置为1int类型的局部变量压入栈

    iload_2

    ()

    将位置为2int类型的局部变量压入栈

    iload_3

    ()

    将位置为3int类型的局部变量压入栈

    fload

    vindex

    将位置为vindexfloat类型的局部变量压入栈

    fload_0

    ()

    将位置为0float类型的局部变量压入栈

    fload_1

    ()

    将位置为1float类型的局部变量压入栈

    fload_2

    ()

    将位置为2float类型的局部变量压入栈

    fload_3

    ()

    将位置为3float类型的局部变量压入栈

    将两个字长的局部变量压入栈

    操作码

    操作数

    说明

    lload

    vindex

    将位置为vindex(vindex+1)long类型的局部变量压入栈

    lload_0

    ()

    将位置为01long类型的局部变量压入栈

    lload_1

    ()

    将位置为12long类型的局部变量压入栈

    lload_2

    ()

    将位置为23long类型的局部变量压入栈

    lload_3

    ()

    将位置为34long类型的局部变量压入栈

    dload

    vindex

    将位置为vindex(vindex+1)double类型的局部变量压入栈

    dload_0

    ()

    将位置为01double类型的局部变量压入栈

    dload_1

    ()

    将位置为12double类型的局部变量压入栈

    dload_2

    ()

    将位置为23double类型的局部变量压入栈

    dload_3

    ()

    将位置为34double类型的局部变量压入栈

    将对象引用局部变量压入栈

    操作码

    操作数

    说明

    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类型值,然后将其存到位置为01的局部变量中

    lstore_1

    ()

    从栈中弹出long类型值,然后将其存到位置为12的局部变量中

    lstore_2

    ()

    从栈中弹出long类型值,然后将其存到位置为23的局部变量中

    lstore_3

    ()

    从栈中弹出long类型值,然后将其存到位置为34的局部变量中

    dstore

    vindex

    从栈中弹出double类型值,然后将其存到位置为vindex(vindex+1)的局部变量中

    dstore_0

    ()

    从栈中弹出double类型值,然后将其存到位置为01的局部变量中

    dstore_1

    ()

    从栈中弹出double类型值,然后将其存到位置为12的局部变量中

    dstore_2

    ()

    从栈中弹出double类型值,然后将其存到位置为23的局部变量中

    dstore_3

    ()

    从栈中弹出double类型值,然后将其存到位置为34的局部变量中

    操作码

    操作数

    说明

    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指令修改过的操作码。


  • 相关阅读:
    python tarfile模块基本使用
    Python shutil模块
    python的gzip库使用方法
    python的gzip库使用方法
    python的gzip库使用方法
    linux 下查看文件修改时间,访问时间,状态改变时间
    linux 下查看文件修改时间,访问时间,状态改变时间
    linux 下查看文件修改时间,访问时间,状态改变时间
    mysqldump使用
    windows 7环境下配置oracle 11g 客户端
  • 原文地址:https://www.cnblogs.com/duzhentong/p/7816573.html
Copyright © 2011-2022 走看看