欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java Class文件结构实例分析(上)

程序员文章站 2022-06-24 23:54:13
...

发表文章之后,发现很多图片显示不了,请阅读我的公众号文章,以获得本文最佳体验:

Java Class文件结构实例分析(上)

 

本文假定读者对Java Class文件格式有一些基本的了解,建议结合相关书籍进行对照阅读。

Class文件格式信息

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

实例代码

package chapter6;
public class TestClass {
    private int m;
    public int inc() {
        return m + 1;
    }
}

使用JDK1.8编译成class文件,然后通过WinHex打开

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

魔数(magic)

类型:u4 
字节地址:00000000~00000003 
值:0xCAFEBABE

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

Class文件版本

次版本号(minor_version)

类型:u2 
字节地址:00000004~00000005 
值:0x0000

主版本号(major_version)

类型:u2 
字节地址:00000006~00000007 
值:0x0034

将0x0034转换为十进制,计算得到52,对应版本号为JDK 1.8。

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

常量池

常量池容量计数值(constant_pool_count)

类型:u2 
字节地址:00000008~00000009 
值:0x0016

将0x0016转换为十进制,计算得到22。由于容量计数是从1开始(如果没有特殊情况,通常都是从0开始),因此常量池中有21项常量,索引值范围为1~21。

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

常量池中每一项常量都是一个表,表开始的第一位是一个u1类型的标志位(tag)。

第1项常量

tag类型:u1 
tag字节地址:0000000A 
tag值:0x07

查表可知这个常量属于CONSTANT_Class_info结构,代表一个类或者接口的符号引用。

name_index类型:u2 
name_index字节地址:0000000B~0000000C 
name_index值:0x0002

0x0002指向了常量池中的第2项常量。

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

第2项常量

tag类型:u1 
tag字节地址:0000000D 
tag值:0x01

查表可知这个常量属于CONSTANT_Utf8_info结构,代表一个UTF-8编码的字符串。

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

length类型:u2 
length字节地址:0000000E~0000000F 
length值:0x0012

将0x0012转换为十进制,计算得到18。

bytes类型:u1 
bytes字节地址:00000010~00000021(length表明地址范围为18个字节) 
bytes值:下方图片浅蓝底对应的所有字节内容

通过WinHex查看,对应内容为chapter6/TestClass,即类的全限定名。

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

通过逐个字节对照ASCII字符表,我们同样可以得到内容为chapter6/TestClass。

  • 获取ASCII字符表:在Linux上执行man ascii,翻页在Tables项可以看到字符表。
  • 查找字符:先找横坐标,再找纵坐标,横竖交叉的位置即为字节对应的字符。

例如0x63为c,0x68为h,0x61为a,0x70为p,0x74为t,0x65为e,0x72为r,连起来代表单词chapter。

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

第3项常量

tag类型:u1 
tag字节地址:00000022 
tag值:0x07

这个常量属于CONSTANT_Class_info结构,代表一个类或者接口的符号引用。

name_index类型:u2 
name_index字节地址:00000023~00000024 
name_index值:0x0004

0x0004指向了常量池中的第4项常量。

第4项常量

tag类型:u1 
tag字节地址:00000025 
tag值:0x01

这个常量属于CONSTANT_Utf8_info结构,代表一个UTF-8编码的字符串。

length类型:u2 
length字节地址:00000026~00000027 
length值:0x0010

将0x0010转换为十进制,计算得到16。

bytes类型:u1 
bytes字节地址:00000028~00000037(length表明地址范围为16个字节) 
bytes值:下方图片浅蓝底对应的所有字节内容

通过WinHex查看,对应内容为java/lang/Object,即类的全限定名。

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

第5项常量

tag类型:u1 
tag字节地址:00000038 
tag值:0x01

这个常量属于CONSTANT_Utf8_info结构,代表一个UTF-8编码的字符串。

length类型:u2 
length字节地址:00000039~0000003A 
length值:0x0001

bytes类型:u1 
bytes字节地址:0000003B(length表明地址范围为1个字节) 
bytes值:0x6D

通过WinHex查看,对应内容为实例变量m。

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

其他常量可以通过类似的方法进行分析,但这样一个个分析确实挺辛苦的。

其实,JDK已经为我们提供了一个Class文件字节码工具:javap,可以让我们较为直观的看到Class文件的字节码内容。

执行命令:javap -verbose TestClass.class,截取常量池部分内容如下:

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

可以看到,版本号及前5个常量与我们分析的结果是一致的。所以,能用1行代码搞定的事儿,就不要用2行(浪费笔墨)。

常量池最后一个字节:000000D8

访问标志(access_flags)

类型:u2 
字节地址:000000D9~000000DA 
值:0x0021

查看类或接口访问标志含义表可知,该类的访问标志为ACC_PUBLIC(0x0001)、ACC_SUPER(0x0020)。

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

另外,通过类的定义public class TestClass,同样可以推断出类的访问标志为ACC_PUBLIC、ACC_SUPER,而ACC_INTERFACE、ACC_ENUM、ACC_FINAL、ACC_ABSTRACT、ACC_ANNOTATION、ACC_SYNTHETIC都可以排除。

所以,access_flags应该为0x0001|0x0020=0x0021,结果与查看字节码相同。

类索引(this_class)

类型:u2 
字节地址:000000DB~000000DC 
值:0x0001

this_class指向常量池的第1个常量,基于前面的分析可知:

  • 第1个常量的类型为Class,Class名称索引指向第2个常量。
  • 第2个常量类型为Utf8,对应内容为chapter6/TestClass。

因此,类索引(this_class)指向的类为chapter6/TestClass。

父类索引(super_class)

类型:u2 
字节地址:000000DD~000000DE 
值:0x0003

同样,super_class指向常量池的第3个常量。

  • 第3个常量的类型为Class,Class名称索引指向第4个常量。
  • 第4个常量类型为Utf8,对应内容为java/lang/Object。

因此,父类索引(super_class)指向的类为java/lang/Object。

接口计数器(interfaces_count)

类型:u2 
字节地址:000000DF~000000E0 
值:0x0000

接口计数器值为0,说明该类没有实现任何接口。

接口表(interfaces)

类索引(this_class)、父类索引(super_class)和接口索引(interfaces)这三项数据共同确定了当前类以及其继承关系,相关常量池内容如下:

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

完整地址范围:000000DB~000000E0

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

字段

字段计数器(fields_count)

类型:u2 
字节地址:000000E1~000000E2 
值:0x0001

说明当前类有1个字段。

字段表(fields)

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

访问标志(access_flags)

类型:u2 
字节地址:000000E3~000000E4 
值:0x0002

对应的访问标志为ACC_PRIVATE。

名称索引(name_index)

类型:u2 
字节地址:000000E5~000000E6 
值:0x0005

对应常量池中的第5项常量,即字段名为m。

描述符(descriptor_index)

类型:u2 
字节地址:000000E7~000000E8 
值:0x0006

对应常量池中的第6项常量,值为I,即int类型。

因此,该字段的定义为private int m;

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

属性计数器(attributes_count)

类型:u2 
字节地址:000000E9~000000EA 
值:0x0000

说明该字段没有属性信息。

属性表(attributes)

无。

字段完整地址范围:000000E1~000000EA

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class 

最后是方法和属性,由于内容复杂度及篇幅原因,我们下篇再续。


 

参考

《Java虚拟机规范》(Java SE 8版)

《深入理解Java虚拟机 JVM高级特性与最佳实践》

 

转载请注明来源:http://zhanjia.iteye.com/blog/2430255

 

个人公众号

二进制之路

 

Java Class文件结构实例分析(上)
            
    
    博客分类: Java读书笔记Java虚拟机(JVM) javajvm虚拟机字节码class