java.class的内容结构与含义

JVM的运行内存结构

虚拟机栈

当方法执行时,会在虚拟机中压入一个栈帧,其中主要存储了(局部变量表,操作数站,动态链接,方法出口),方法中的数据存储在局部变量表中。 数据单元为32位(局部变量槽Slot), 如果一个数据长度为(64位)如 (long,double)基本类型。则占用两个Slot。

方法区

方法区存储了加载到JVM 的类信息,类的元数据信息主要包括了类的接口,名称等描述信息,其中最主要的为(常量池表), 其中包含了各种数据的引用, 其中产生的数据实则存放在运行时常量池中。方法区中主要存储了一些以class为主要的数据。
注:jdk8中方法区的实现为元空间

你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。

Class类的文件结构

ClassFile { 
    u4 magic;  // 魔法数字,表明当前文件是.class文件,固定0xCAFEBABE
    u2 minor_version; // 分别为Class文件的副版本和主版本
    u2 major_version; 
    u2 constant_pool_count; // 常量池计数
    cp_info constant_pool[constant_pool_count-1];  // 常量池内容
    u2 access_flags; // 类访问标识
    u2 this_class; // 当前类
    u2 super_class; // 父类
    u2 interfaces_count; // 实现的接口数
    u2 interfaces[interfaces_count]; // 实现接口信息
    u2 fields_count; // 字段数量
    field_info fields[fields_count]; // 包含的字段信息 
    u2 methods_count; // 方法数量
    method_info methods[methods_count]; // 包含的方法信息
    u2 attributes_count;  // 属性数量
    attribute_info attributes[attributes_count]; // 各种属性
}

常量池数据

package demo;

public class TestClass {

    public static int i ;

    private int m;

    public int inc() {
        return m + 1;
    }

}

编译后的TestClass.class以16进制显示
在这里插入图片描述
第一个数据
(0x00000008,0x00000009) 为 0x0017 代表常量池中有 22(23-1)个类的字面量和符号引用,其它具体的具体数据在加载class后置入运行时常量池中

第二个数据
0x00000009 为 0x0a(类的方法的符号引用)
在这里插入图片描述
也就是说 第1个index(符号引用)指向 (0x0004)常量池的偏移4个的地址 , 第2个index(符号引用)指向(0x0013)常量池偏移19个的地址。

所以常量池偏移量为0x0004的内存数据为:
在这里插入图片描述
其中主要是指向全限定名常量项的索引,所以这个全限定名指向了一个
在这里插入图片描述
显然,java中的编码默认为UTF-8, 最终该bytes 解码后的数据为java/lang/Object

第二个为index 指向了0x0019,类型为

在这里插入图片描述
显然,又是两个引用,第一个引用指向了0x0008, 第二个指向了 0x0009

0x0008 为 一个,0x0009 为一个 ()v 他们虽然是UTF-8类型,但JVM会对这些字符串新型解析
常量池中所有的内容

"C:\Program Files (x86)\Java\jdk1.8.0_271/bin/javap.exe" -v demo.TestClass
Classfile /E:/project/untitled/demo/target/classes/demo/TestClass.class
  Last modified 2021-2-25; size 375 bytes
  MD5 checksum 0b68fcee12eb3db08e1e697dc369e545
  Compiled from "TestClass.java"
public class demo.TestClass
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#19         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#20         // demo/TestClass.m:I
   #3 = Class              #21            // demo/TestClass
   #4 = Class              #22            // java/lang/Object
   #5 = Utf8               i
   #6 = Utf8               I
   #7 = Utf8               m
   #8 = Utf8               <init>
   #9 = Utf8               ()V
  #10 = Utf8               Code
  #11 = Utf8               LineNumberTable
  #12 = Utf8               LocalVariableTable
  #13 = Utf8               this
  #14 = Utf8               Ldemo/TestClass;
  #15 = Utf8               inc
  #16 = Utf8               ()I
  #17 = Utf8               SourceFile
  #18 = Utf8               TestClass.java
  #19 = NameAndType        #8:#9          // "<init>":()V
  #20 = NameAndType        #7:#6          // m:I
  #21 = Utf8               demo/TestClass
  #22 = Utf8               java/lang/Object

至此, 常量池的数据内容完毕

u4 magic;  // 魔法数字,表明当前文件是.class文件,固定0xCAFEBABE
u2 minor_version; // 分别为Class文件的副版本和主版本
u2 major_version; 
u2 constant_pool_count; // 常量池计数
cp_info constant_pool[constant_pool_count-1];  // 常量池内容

访问标志

0x000000d4 常量池数据的结束
(0x000000d5,0x000000d6),类访问标识 0x0021 代表了

在这里插入图片描述

当前类

(0x000000d6,0x000000d7) 为 0x0003 可见又指向了 常量池中的第三个

父类

(0x000000d9,0x000000da) 为 0x0004 指向了常量池中的第四个

接口数

(0x000000d9,0x000000da)
0个

接口数组

空 则不占用空间

字段数量

在这里插入图片描述
2个

字段数组

字段表结构
public static int i ;

0x09 代表了常量+公有

在这里插入图片描述
0x0005代表指向了常量池中的5第五项,即"i"

0x0006代表了常量池中的第六项,即"I", 含义是int 类型
0x0000代表了属性表指针为空指针

方法数量

在这里插入图片描述
2个

方法数组

在这里插入图片描述
在这里插入图片描述
0x0001代表了access_flags : public , 0x0008代表了常量池中的#8,
在这里插入图片描述
0x0009代表了常量池中的#9,
在这里插入图片描述
0x0001代表了1个属性

属性的数据结构为

在这里插入图片描述

属性的第一个属性的 attribute_name_index 为 0x000a 即常量池中的#10
在这里插入图片描述
attribute_length 的长度为 0x0000002f = 16 * 2 + 15 = 47
在这里插入图片描述

所以接下来的47B为:
在这里插入图片描述
因为属性是Code 那么 Code数据表结构为:

在这里插入图片描述
前两个已经介绍了,第三个max_stack 为 0x0001 即最大栈为1,
在这里插入图片描述

max_locals 为 0x0001本地变量表最大为1(隐式传递this),
在这里插入图片描述

code_length 为 5

在这里插入图片描述

code 为
在这里插入图片描述

在这里插入图片描述
u2 exception_table_length;为 0
在这里插入图片描述
exception_table[exception_table_length]; 为 没有申请内存
u2 attributes_count;为;2

在这里插入图片描述
attribute_info attributes[attributes_count]为, 可以猜出那两个就是LineNumberTable 和 LocalVariableTable
在这里插入图片描述

LineNumberTable 的数据结构为:
在这里插入图片描述

所以 name_index 为
在这里插入图片描述

指向常量池的#11
在这里插入图片描述
长度为:6

在这里插入图片描述

LineNumberTable_info 数据结构为:

{   u2 start_pc;
    u2 line_number;	
}

这里由于不知道为什么,理应听该是24个字节, 这里只有6个字节, 数据展位类似这样(可能由于是x86环境?)

在这里插入图片描述

解析后的数据为:
在这里插入图片描述

下一个为0x0c 即 #12为
在这里插入图片描述

具体数据结构为:
在这里插入图片描述

LocalVariableTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_table_length;
    {   u2 start_pc;
        u2 length;
        u2 name_index;
        u2 descriptor_index;
        u2 index;
    } local_variable_table[local_variable_table_length];
}

其中的含义为;
在这里插入图片描述
在这里插入图片描述
0x000c为 指向常量池的#12
在这里插入图片描述

0x0001 为一个属性长度
在这里插入图片描述

0x0000 为 start_pc为0, 即该变量的偏移地址
0x0005 为lenght 为 5 变量的作用域长度
0x000d 为 # 13
在这里插入图片描述

0x000e 为 指向常量池的 #14
在这里插入图片描述
0x0000 为 该变量在变量槽的位置
在这里插入图片描述

这里有个问题就是 解析LineNumberTable 的时候和解析LocalVariableTable与字节码,和 字节码的大小对应不上。

第二个方法为
在这里插入图片描述
在这里插入图片描述
复习一下,即共有#15
在这里插入图片描述
#16的int返回值,
有1个属性, 属性为0x0a = #10 = Code

Code的数据结构为

Code_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 max_stack;
    u2 max_locals;
    u4 code_length;
    u1 code[code_length];
    u2 exception_table_length;
    {   u2 start_pc;
        u2 end_pc;
        u2 handler_pc;
        u2 catch_type;
    } exception_table[exception_table_length];
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

在这里插入图片描述

属性长度为:0x0031 = 16*3 + 1 = 49
2个栈
1个变量表

属性数量

1个

0x11 = #17

在这里插入图片描述

在这里插入图片描述
接下来很明显
Class至此解析完毕

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值