JVM-01

2019-06-19  本文已影响0人  平头哥2

编写HelloWorld.java

public class HelloWorld{
    public static void main(String[] args){
        System.out.println("HelloWorld");
    }
}

编译:

javac HelloWorld.java

javap的使用:

D:\>javap
用法: javap <options> <classes>
其中, 可能的选项包括:
  -help  --help  -?        输出此用法消息
  -version                 版本信息
  -v  -verbose             输出附加信息
  -l                       输出行号和本地变量表
  -public                  仅显示公共类和成员
  -protected               显示受保护的/公共类和成员
  -package                 显示程序包/受保护的/公共类
                           和成员 (默认)
  -p  -private             显示所有类和成员
  -c                       对代码进行反汇编
  -s                       输出内部类型签名
  -sysinfo                 显示正在处理的类的
                           系统信息 (路径, 大小, 日期, MD5 散列)
  -constants               显示最终常量
  -classpath <path>        指定查找用户类文件的位置
  -cp <path>               指定查找用户类文件的位置
  -bootclasspath <path>    覆盖引导类文件的位置

其中-c -v -l -p -s是最常用的

-c 选项

$ javap -c HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
  public HelloWorld(); // ##这里默认会添加一个构造方法
    Code:
       0: aload_0   // 
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);//## main函数
    Code:
       0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #3                  // String HelloWorld
       5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}

解释:

  1. aload_0 这个操作码是 aload_x 格式操作码中的一个。它们用来把**对象引用**加载到操作数栈。 x 表示正在被访问的局部变量数组的位置。在这里的 0 代表什么呢?我们知道非静态的函数都有第一个默认参数,那就是 this,这里的 aload_0 就是把 this 入栈
  2. invokespecial #1,invokespecial 指令调用实例初始化方法、私有方法、父类方法,#1 指的是常量池中的第一个,这里是方法引用java/lang/Object."<init>":()V,也即构造器函数
  3. return,这个操作码属于 ireturn、lreturn、freturn、dreturn、areturn 和 return 操作码组中的一员,其中 i 表示 int,返回整数,同类的还有 l 表示 long,f 表示 float,d 表示 double,a 表示 对象引用。没有前缀类型字母的 return 表示返回 void
  4. getstatic #2,getstatic 获取指定类的静态域,并将其值压入栈顶,#2 代表常量池中的第 2 个,这里表示的是java/lang/System.out:Ljava/io/PrintStream;,其实就是java.lang.System 类的静态变量 out(类型是 PrintStream)
  5. ldc #3、,ldc 用来将常量从运行时常量池压栈到操作数栈,#3 代表常量池的第三个(字符串 Hello, World)
  6. invokevirtual #4,invokevirutal 指令调用一个对象的实例方法,#4 表示 PrintStream.println(String) 函数引用,并把栈顶两个元素出栈

-v选项

$ javap -v HelloWorld.class
Classfile /D:/ideaproject/jvm/HelloWorld.class
  Last modified 2019-6-19; size 411 bytes
  MD5 checksum 30c120f376b16361b854fd5c0d695ea6
  Compiled from "HelloWorld.java"
public class HelloWorld
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#15         // java/lang/Object."<init>":()V
   #2 = Fieldref           #16.#17        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #18            // HelloWorld
   #4 = Methodref          #19.#20        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #18            // HelloWorld
   #6 = Class              #21            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               SourceFile
  #14 = Utf8               HelloWorld.java
  #15 = NameAndType        #7:#8          // "<init>":()V
  #16 = Class              #22            // java/lang/System
  #17 = NameAndType        #23:#24        // out:Ljava/io/PrintStream;
  #18 = Utf8               HelloWorld
  #19 = Class              #25            // java/io/PrintStream
  #20 = NameAndType        #26:#27        // println:(Ljava/lang/String;)V
  #21 = Utf8               java/lang/Object
  #22 = Utf8               java/lang/System
  #23 = Utf8               out
  #24 = Utf8               Ljava/io/PrintStream;
  #25 = Utf8               java/io/PrintStream
  #26 = Utf8               println
  #27 = Utf8               (Ljava/lang/String;)V
{
  public HelloWorld();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String HelloWorld
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 3: 0
        line 4: 8
}
SourceFile: "HelloWorld.java"

-l选项

$ javap -l HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
  public HelloWorld();
    LineNumberTable:
      line 1: 0

  public static void main(java.lang.String[]);
    LineNumberTable:
      line 3: 0
      line 4: 8
}

-s选项:输出签名的类型描述符

$ javap -s HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
  public HelloWorld();//构造方法
    descriptor: ()V //描述: ()表示没有参数,V表示返回值为void

  public static void main(java.lang.String[]); //main方法
    descriptor: ([Ljava/lang/String;)V // ([Ljava/lang/String;)表示参数为数组
}

修改java代码如下:

public class HelloWorld{

    public int test01(byte b1, short s, int a, long l2, float f1, double d, char c, boolean bool,Integer it,String str){
        return 0;
    }
}

重新编译,查看方法签名

$ javap -s HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
  public HelloWorld();
    descriptor: ()V

  public int test01(byte, short, int, long, float, double, char, boolean, java.lang.Integer, java.lang.String);
    descriptor: (BSIJFDCZLjava/lang/Integer;Ljava/lang/String;)I
}

查看调试信息:

编译阶段加上-g参数:

$ javac -g HelloWorld.java

-l 选项

$ javap -l HelloWorld.class
Compiled from "HelloWorld.java"
public class HelloWorld {
  public HelloWorld();
    LineNumberTable:
      line 1: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       5     0  this   LHelloWorld;
//this表明构造方法默认第一个参数是this,LHelloWorld,表示构造方法名字和类名一样
  public static void main(java.lang.String[]);
    LineNumberTable:
      line 4: 0
      line 5: 8
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       9     0  args   [Ljava/lang/String;
//args:参数名字,[Ljava/lang/String:表示参数为String数组,数组以 '[L' 开头
  public int test01(byte, short, int, long, float, double, char, boolean, java.lang.Integer, java.lang.String);
    LineNumberTable:
      line 8: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       2     0  this   LHelloWorld;//this表明成员方法默认第一个参数是this
          0       2     1    b1   B //第二个参数名字是b1, 类型为byte,B代表byte
          0       2     2     s   S //第三个参数名字是s, 类型为short,S代表short
          0       2     3     a   I //第四个参数名字是a, 类型为int,I代表int
          0       2     4    l2   J //第五个参数名字是l2, 类型为long,J代表long
          0       2     6    f1   F //第六个参数名字是f1, 类型为float,F代表float
          0       2     7     d   D //第七个参数名字是d, 类型为short,D代表double
          0       2     9     c   C //第八个参数名字是c, 类型为char,C代表char
          0       2    10  bool   Z //第九个参数名字是bool, 类型为boolean,Z代表boolean
          0       2    11    it   Ljava/lang/Integer; //第十个参数名字是it, 类型为Integer
                                   //引用类型以L开头
          0       2    12   str   Ljava/lang/String; //第十一个参数名字是str, 类型为String
}

-v 选项

$ javap -v HelloWorld.class
Classfile /D:/ideaproject/jvm/HelloWorld.class
  Last modified 2019-6-19; size 874 bytes
  MD5 checksum ee15f31a14c1582634907a7504bf4cf7
  Compiled from "HelloWorld.java"
public class HelloWorld
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#42         // java/lang/Object."<init>":()V
   #2 = Fieldref           #43.#44        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #45            // helloworld
   #4 = Methodref          #46.#47        // java/io/PrintStream.println:(Ljava/lang/String;)V
   #5 = Class              #48            // HelloWorld
   #6 = Class              #49            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               LHelloWorld;
  #14 = Utf8               main
  #15 = Utf8               ([Ljava/lang/String;)V
  #16 = Utf8               args
  #17 = Utf8               [Ljava/lang/String;
  #18 = Utf8               test01
  #19 = Utf8               (BSIJFDCZLjava/lang/Integer;Ljava/lang/String;)I
  #20 = Utf8               b1
  #21 = Utf8               B
  #22 = Utf8               s
  #23 = Utf8               S
  #24 = Utf8               a
  #25 = Utf8               I
  #26 = Utf8               l2
  #27 = Utf8               J
  #28 = Utf8               f1
  #29 = Utf8               F
  #30 = Utf8               d
  #31 = Utf8               D
  #32 = Utf8               c
  #33 = Utf8               C
  #34 = Utf8               bool
  #35 = Utf8               Z
  #36 = Utf8               it
  #37 = Utf8               Ljava/lang/Integer;
  #38 = Utf8               str
  #39 = Utf8               Ljava/lang/String;
  #40 = Utf8               SourceFile
  #41 = Utf8               HelloWorld.java
  #42 = NameAndType        #7:#8          // "<init>":()V
  #43 = Class              #50            // java/lang/System
  #44 = NameAndType        #51:#52        // out:Ljava/io/PrintStream;
  #45 = Utf8               helloworld
  #46 = Class              #53            // java/io/PrintStream
  #47 = NameAndType        #54:#55        // println:(Ljava/lang/String;)V
  #48 = Utf8               HelloWorld
  #49 = Utf8               java/lang/Object
  #50 = Utf8               java/lang/System
  #51 = Utf8               out
  #52 = Utf8               Ljava/io/PrintStream;
  #53 = Utf8               java/io/PrintStream
  #54 = Utf8               println
  #55 = Utf8               (Ljava/lang/String;)V
{
  public HelloWorld();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   LHelloWorld;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #3                  // String helloworld
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 4: 0
        line 5: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  args   [Ljava/lang/String;

  public int test01(byte, short, int, long, float, double, char, boolean, java.lang.Integer, java.lang.String);
    descriptor: (BSIJFDCZLjava/lang/Integer;Ljava/lang/String;)I
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=13, args_size=11 //参数个数为11
         0: iconst_0
         1: ireturn
      LineNumberTable:
        line 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       2     0  this   LHelloWorld;
            0       2     1    b1   B
            0       2     2     s   S
            0       2     3     a   I
            0       2     4    l2   J
            0       2     6    f1   F
            0       2     7     d   D
            0       2     9     c   C
            0       2    10  bool   Z
            0       2    11    it   Ljava/lang/Integer;
            0       2    12   str   Ljava/lang/String;
}
SourceFile: "HelloWorld.java"

以16进制查看HelloWorld.class文件:

# 将class文件转换成16进制
$ xxd HelloWorld.class HelloWorld.txt
$ ls
HelloWorld.class  HelloWorld.java  HelloWorld.txt
$ cat HelloWorld.txt
00000000: cafe babe 0000 0034 001c 0a00 0600 0f09  .......4........
00000010: 0010 0011 0800 120a 0013 0014 0700 1207  ................
00000020: 0015 0100 063c 696e 6974 3e01 0003 2829  .....<init>...()
00000030: 5601 0004 436f 6465 0100 0f4c 696e 654e  V...Code...LineN
00000040: 756d 6265 7254 6162 6c65 0100 046d 6169  umberTable...mai
00000050: 6e01 0016 285b 4c6a 6176 612f 6c61 6e67  n...([Ljava/lang
00000060: 2f53 7472 696e 673b 2956 0100 0a53 6f75  /String;)V...Sou
00000070: 7263 6546 696c 6501 000f 4865 6c6c 6f57  rceFile...HelloW
00000080: 6f72 6c64 2e6a 6176 610c 0007 0008 0700  orld.java.......
00000090: 160c 0017 0018 0100 0a48 656c 6c6f 576f  .........HelloWo
000000a0: 726c 6407 0019 0c00 1a00 1b01 0010 6a61  rld...........ja
000000b0: 7661 2f6c 616e 672f 4f62 6a65 6374 0100  va/lang/Object..
000000c0: 106a 6176 612f 6c61 6e67 2f53 7973 7465  .java/lang/Syste
000000d0: 6d01 0003 6f75 7401 0015 4c6a 6176 612f  m...out...Ljava/
000000e0: 696f 2f50 7269 6e74 5374 7265 616d 3b01  io/PrintStream;.
000000f0: 0013 6a61 7661 2f69 6f2f 5072 696e 7453  ..java/io/PrintS
00000100: 7472 6561 6d01 0007 7072 696e 746c 6e01  tream...println.
00000110: 0015 284c 6a61 7661 2f6c 616e 672f 5374  ..(Ljava/lang/St
00000120: 7269 6e67 3b29 5600 2100 0500 0600 0000  ring;)V.!.......
00000130: 0000 0200 0100 0700 0800 0100 0900 0000  ................
00000140: 1d00 0100 0100 0000 052a b700 01b1 0000  .........*......
00000150: 0001 000a 0000 0006 0001 0000 0001 0009  ................
00000160: 000b 000c 0001 0009 0000 0025 0002 0001  ...........%....
00000170: 0000 0009 b200 0212 03b6 0004 b100 0000  ................
00000180: 0100 0a00 0000 0a00 0200 0000 0300 0800  ................
00000190: 0400 0100 0d00 0000 0200 0e              ...........

class文件各个部分的解释

  1. 魔数

    cafe babe

    class 的魔数为 0xCAFEBABE, 这个魔数是 JVM 识别 .class 文件的标志,虚拟机在加载类文件之前会先检查这四个字节,如果不是 0xCAFEBABE 则拒绝加载该文件

上一篇下一篇

猜你喜欢

热点阅读