类的class字节码文件,学这一篇就够了

涉及知识点:符号引用和直接引用https://blog.csdn.net/qq_34402394/article/details/72793119?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1JVM指令集编写一个类:HelloW.
摘要由CSDN通过智能技术生成

涉及知识点:

  • 符号引用和直接引用

https://blog.csdn.net/qq_34402394/article/details/72793119?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1

  • JVM指令集

 

编写一个类:HelloWorld.java

文件所在目录:/home/work/test/

public class HelloWorld {

    private static int num = 0;
    public String welcome = "HelloWorld";
    
    public static void main(String[] args) {

        String[] strArray = {"cainiao", "yuanyuan"};

        for (int i = 0; i < 10; i++) {
            HelloWorld.num++;
            
            if(i == 5) {
                continue;
            }
            
            System.out.println("HelloWorld!");
        }
    }

    private long myMethod() {
        return 99L;
    }
}

注意,代码里不需要写包路径,因为我们等会儿是直接进入到HelloWorld.java所在位置执行编译操作,如果有包路径,需要再建立对应代码目录,徒增干扰。

 

编译类文件

进入/home/work/test/目录

执行:

javac HelloWorld.java

生成HelloWorld.class文件,这就是类HelloWorld.java的字节码文件。

 

使用工具打开HelloWorld.class字节码文件

idea推荐插件jclasslib bytecode viewer,官网安装插件地址:https://plugins.jetbrains.com/plugin/9248-jclasslib-bytecode-viewer

使用该插件打开字节码,界面如下:

查看翻译后的字节码和16进制字节码对应,可使用classpy工具。

使用classpy打开HelloWorld.class,界面如下:

左侧为字节码内容解析后的可视化结构,右侧为对应的16进制字节码。

Java官方虚拟机规范中,对类的class文件格式说明文档:https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html 我们所有的讲解都将以官方文档为准。

class字节码文件整体结构:

ClassFile {
    u4             magic;
    u2             minor_version;
    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];
}

上述整体结构的描述格式仅仅是表示出class文件中有哪些信息,以及每项信息的长度或类型,并不是class文件真正的格式,不要误会!后文类似结构描述均是如此。

其中的u2、u4:

在计算机中,8bit=1Byte(8位等于1个字节)。类文件中的各项信息长度不同,使用u2、u4表示该项信息的长度,u表示无符号整数。

  • magic:信息长度为4个字节,则使用u4表示
  • minor_version:信息长度为2个字节,则使用u2表示

其中的cp_info、field_info、method_info、attribute_info:

  • cp_info:常量池中所有常量的列表
  • field_info:类中的具体变量表(指代码中的num、welcome,不包括方法中的变量strArray)
  • method_info:类中的方法表
  • attribute_info:类中的属性表(类本身的属性信息,不是类中的字段,类中的字段在field_info项表示)

HelloWord.class中对应上述类文件格式的各项信息如下:

简要介绍class文件各部分内容

先对class文件中的各个部分进行简要介绍,然后对每个部分详细介绍,所以这一段看不懂没关系,先大致了解。

  • magic:魔数,是class文件的标识符
  • minor_version, major_version:表示编译该class文件使用的JDK版本号
  • constant_pool_count:该类的常量池中常量数量
  • constant_pool[]:该类常量池中的常量明细表
  • access_flags:该类的访问权限标识符,如public、private、abstract
  • this_class:当前类自身是谁,保存的是当前类的名字在常量池中对应常量的索引值(对应上述示例,this_class指向常量池中的一个字符串常量:HelloWorld)
  • super_class:表示当前类的父类是谁,取值只能为0或父类的名字在常量池中对应常量的索引值(对应上述示例,super_class指向常量池中的一个字符串常量:java/lang/Object。当本类即为Object类时,super_class取值为0)
  • interfaces_count:表示当前类直接实现的接口数量
  • interfaces[]:表示当前类直接实现的接口明细表
  • fields_count:表示当前类中字段的数量
  • fields[]:表示当前类中字段明细表(对应上述示例中的变量:num、welcome)
  • methods_count:表示当前类中方法的数量
  • methods[]:表示当前类中方法明细表
  • attributes_count:表示当前类的属性数量
  • attributes[]:表示当前类的属性明细表(要区别属性和字段,类的属性如当前class文件对应的源代码文件名:HelloWorld.java)

详细介绍class文件各部分内容

下面对类文件结构的各部分逐一解释。

magic:魔数

是class文件的标识符,长度:4字节。

当文件的前4个字节为0xCAFEBABY时,JVM才会认为当前文件为java类的字节码文件。

尝试使用文本编辑器修改HelloWorld.class文件,如修改为“CAFE BABA”:

执行:

java HelloWorld

JVM报错:魔数错误。(错误信息中的1667327589,是16进制0xCAFEBABE的10进制数值)

minor_version,major_version:次版本号(小版本号),主版本号(大版本号)

二者共同组成一个版本号,表示编译出当前字节码文件所使用的JDK版本号。

minor_version=0x0000=0,major_version=0x0034=52,则编译出当前字节码文件所使用的JDK版本号是:52.0。

再根据以下JDK版本与class文件版本号对应关系(第1列是JDK版本,第2列是class文件版本号),可知编译使用的JDK版本是:8(即JDK8)。

第3列表示JDK版本对应可处理的class文件版本号区间,如JDK8支持处理版本号在[45~52]之间的class文件。

1593046150870

官方文档中说明:

JDK1.0.2版本,支持45.0~45.3版本的class文件

JDK1.1.*版本,支持45.0~45.65535版本的class文件(即16进制版本号区间:0x0000~0xffff)

JDK1.2及以上版本,class文件版本号支持情况如上表所示。

constant_pool_count:常量池中常量的数量

常量池中常量数量=(下面)常量表中常量数-1

constant_pool:常量池中的常量表

常量池表是class文件中的重要组成部分。说到java中的常量池,其实有两部分:

  1. 静态常量池:就是class文件中写到的常量池;
  2. 运行时常量池:class文件被加载到JVM内存之后,class文件中的常量池保存在了方法区。通常说道“常量池”都是指运行时常量池。

常量池表中描述每个常量信息的格式:

cp_info {
    u1 tag;
    u1 info[];
}

tag:常量池中描述每个常量时,都需要一个1字节长度的tag字段,表示该常量的类型。JVM规范中官方给出的常量类型和对应的数值如下表所示:

Constant Type(常量类型) Value 解释
CONSTANT_Class 7 类或接口【本身】(完全限定名)的常量
CONSTANT_Fieldref 9 类或接口中【字段】的符号引用
CONSTANT_Methodref 10 类或接口中【普通方法】(非接口)的符号引用
CONSTANT_InterfaceMethodref 11 接口中接口【方法】的符号引用
CONSTANT_String 8 表示java.lang.String类型字符串常量
CONSTANT_Integer 3 表示4字节int型数值常量(实际数值)
CONSTANT_Float 4 表示4字节float型数值常量(实际数值)
CONSTANT_Long 5 表示8字节long型数值常量(实际数值)
CONSTANT_Double 6 表示8字节double型数值常量(实际数值)
CONSTANT_NameAndType 12 表示字段或方法的【类型+名称】符号引用
CONSTANT_Utf8 1 字符串常量的值!(实际字符串的值)
CONSTANT_MethodHandle 15 表示方法句柄
CONSTANT_MethodType 16 表示方法类型
CONSTANT_InvokeDynamic
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值