上一篇笔记的内容大部分没有实际动手操作,因此决定完成这个完整的练习并记录下来。
源代码如下:
package com.learn.jvm; /** * @author * @Description * @date 2019/09/05 16:31 */ public class Test { String str = "Welcome"; private int x = 5; public static Integer num = 10; public static void main(String[] args) { Test test = new Test(); test.setX(8); num = 20; } public void setX(int x) { this.x = x; } }
编译后在Windows平台下用HexEditor打开,得到结果如下,由于该软件似乎不支持将内容复制出来,因此截图
javap -verbose的输出结果如下
D:\workspace-learn\common-learn\learn-classloader\target\classes\com\learn\jvm>javap -verbose Test 警告: 二进制文件Test包含com.learn.jvm.Test Classfile /D:/workspace-learn/common-learn/learn-classloader/target/classes/com/learn/jvm/Test.class Last modified 2019-9-5; size 814 bytes MD5 checksum d9651b05ecd94c86c354ab2551983cea Compiled from "Test.java" public class com.learn.jvm.Test SourceFile: "Test.java" minor version: 0 major version: 51 flags: ACC_PUBLIC, ACC_SUPER Constant pool: #1 = Methodref #10.#34 // java/lang/Object."<init>":()V #2 = String #35 // Welcome #3 = Fieldref #5.#36 // com/learn/jvm/Test.str:Ljava/lang/String; #4 = Fieldref #5.#37 // com/learn/jvm/Test.x:I #5 = Class #38 // com/learn/jvm/Test #6 = Methodref #5.#34 // com/learn/jvm/Test."<init>":()V #7 = Methodref #5.#39 // com/learn/jvm/Test.setX:(I)V #8 = Methodref #40.#41 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #9 = Fieldref #5.#42 // com/learn/jvm/Test.num:Ljava/lang/Integer; #10 = Class #43 // java/lang/Object #11 = Utf8 str #12 = Utf8 Ljava/lang/String; #13 = Utf8 x #14 = Utf8 I #15 = Utf8 num #16 = Utf8 Ljava/lang/Integer; #17 = Utf8 <init> #18 = Utf8 ()V #19 = Utf8 Code #20 = Utf8 LineNumberTable #21 = Utf8 LocalVariableTable #22 = Utf8 this #23 = Utf8 Lcom/learn/jvm/Test; #24 = Utf8 main #25 = Utf8 ([Ljava/lang/String;)V #26 = Utf8 args #27 = Utf8 [Ljava/lang/String; #28 = Utf8 test #29 = Utf8 setX #30 = Utf8 (I)V #31 = Utf8 <clinit> #32 = Utf8 SourceFile #33 = Utf8 Test.java #34 = NameAndType #17:#18 // "<init>":()V #35 = Utf8 Welcome #36 = NameAndType #11:#12 // str:Ljava/lang/String; #37 = NameAndType #13:#14 // x:I #38 = Utf8 com/learn/jvm/Test #39 = NameAndType #29:#30 // setX:(I)V #40 = Class #44 // java/lang/Integer #41 = NameAndType #45:#46 // valueOf:(I)Ljava/lang/Integer; #42 = NameAndType #15:#16 // num:Ljava/lang/Integer; #43 = Utf8 java/lang/Object #44 = Utf8 java/lang/Integer #45 = Utf8 valueOf #46 = Utf8 (I)Ljava/lang/Integer; { java.lang.String str; flags: public static java.lang.Integer num; flags: ACC_PUBLIC, ACC_STATIC public com.learn.jvm.Test(); flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: aload_0 5: ldc #2 // String Welcome 7: putfield #3 // Field str:Ljava/lang/String; 10: aload_0 11: iconst_5 12: putfield #4 // Field x:I 15: return LineNumberTable: line 8: 0 line 9: 4 line 10: 10 LocalVariableTable: Start Length Slot Name Signature 0 16 0 this Lcom/learn/jvm/Test; public static void main(java.lang.String[]); flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #5 // class com/learn/jvm/Test 3: dup 4: invokespecial #6 // Method "<init>":()V 7: astore_1 8: aload_1 9: bipush 8 11: invokevirtual #7 // Method setX:(I)V 14: bipush 20 16: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 19: putstatic #9 // Field num:Ljava/lang/Integer; 22: return LineNumberTable: line 14: 0 line 15: 8 line 16: 14 line 17: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 args [Ljava/lang/String; 8 15 1 test Lcom/learn/jvm/Test; public void setX(int); flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=2 0: aload_0 1: iload_1 2: putfield #4 // Field x:I 5: return LineNumberTable: line 20: 0 line 21: 5 LocalVariableTable: Start Length Slot Name Signature 0 6 0 this Lcom/learn/jvm/Test; 0 6 1 x I static {}; flags: ACC_STATIC Code: stack=1, locals=0, args_size=0 0: bipush 10 2: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 5: putstatic #9 // Field num:Ljava/lang/Integer; 8: return LineNumberTable: line 11: 0 }
同时贴出Java字节码整体结构图便于对比查看
以下开始逐个字节进行分析
第1~4个字节:ca fe ba be 为魔数
第5~6个字节:00 00 代表 minor version ,值为0
第7~8个字节:00 33 代表 major version ,值为51
第9~10个字节:00 2f ,换算成十进制为 32+15 = 47 ,代表常量池中共有46个常量(除去一个为null保留的常量),我们通过查看上面 avap -verbose打印出来的信息可以验证,确实是这样的
接下来是具体的常量分析,所以将常量池中的数据类型结构贴出来
(以下为第1个变量)
第11~12个字节:0a 00