深入理解Java Class文件格式
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了 深入理解Java Class文件格式相关的知识,希望对你有一定的参考价值。
转载:http://blog.csdn.net/zhangjg_blog/article/details/22091529
本专栏列前面的一系列博客, 对Class文件中的一部分数据项进行了介绍。 本文将会继续介绍class文件中未讲解的信息。 先回顾一下上面一篇文章。 在上一篇博客中, 我们介绍了:
- this_class 对当前类的描述
- super_class 对当前类的超类的描述
- interfaces_count 当前类直接实现的接口的数量或当前接口直接继承的接口的数量
- interfaces 对当前类或当前接口直接实现或继承的所有接口的描述
详细信息请移步至上一篇博客 深入理解Java Class文件格式(六)。 更多关于Java Class文件和JVM的文章请关注我的专栏深入理解Java语言 。
下面继续介绍class文件中的其他信息。
class文件中的fields_count和fields
(1)access_flags
其中access_flags占两个字节, 描述的是字段的访问标志信息。 这里就不在详细介绍了, 下面给出一张表格(该表格来自《深入Java虚拟机》):
标志位名称 | 值 | 含义 | 设定者 |
ACC_PUBLIC | 0x0001 | 字段被设为public | 类和接口 |
ACC_PRIVATE | 0x0002 | 字段被设为private | 类 |
ACC_PROTECTED | 0x0004 | 字段被设为protected | 类 |
ACC_STATIC | 0x0008 | 字段被设为static | 类和接口 |
ACC_FINAL | 0x0010 | 字段被设为final | 类和接口 |
ACC_VOLATILE | 0x0040 | 字段被设为volatile | 类 |
ACC_TRANSIENT | 0x0080 | 字段被设为transient | 类 |
(2)name_index
access_flags下面的两个字节是name_index, 这是一个指向常量池的索引, 它描述的是当前字段的字段名。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前字段的字段名。
(3)descriptor_index
- package com.jg.zhang;
- public class Programer extends Person{
- private Computer computer;
- public Programer(Computer computer){
- this.computer = computer;
- }
- public void doWork(){
- computer.calculate();
- }
- }
- Constant pool:
- .........
- .........
- #5 = Utf8 computer
- #6 = Utf8 Lcom/jg/zhang/Computer;
- .........
- .........
- {
- private com.jg.zhang.Computer computer;
- flags: ACC_PRIVATE
- .........
- .........
- }
从反编译的结果可以看出, 源文件中定义了一个Computer类型的字段computer, 并且是private的。 然后常量池中有这个字段的字段名和描述符。 其中常量池第五项的CONSTANT_Utf8_info是字段名, 第六项的CONSTANT_Utf8_info是该字段的描述符。这里有一点需要说明, 在反编译Programer.class时,由于computer是私有的, 要加- private选项, 否则的话, 虽然常量池中有字段引用信息, 但是不会输出字段信息, 即下面这两行不会输出:
- private com.jg.zhang.Computer computer;
- flags: ACC_PRIVATE
- javap -c -v -private -classpath . com.jg.zhang.Programer
class文件中的methods_count和methods
标志位名称 | 标志值 | 设定含义 | 设定者 |
ACC_PUBLIC | 0x0001 | 方法设为public | 类和接口 |
ACC_PRIVATE | 0x0002 | 方法设为private | 类 |
ACC_PROTECTED | 0x0004 | 方法设为protected | 类 |
ACC_STATIC | 0x0008 | 方法设为static | 类 |
ACC_FINAL | 0x0010 | 方法设为final | 类 |
ACC_SYNCHRONIZED | 0x0020 | 方法设为sychronized | 类 |
ACC_NATIVE | 0x0100 | 方法设为native | 类 |
ACC_ABSTRACT | 0x0400 | 方法设为abstract | 类和接口 |
ACC_STRICT | 0x0800 | 方法设为strictFP | 类和接口的<clinit>方法 |
(2)name_index
access_flags下面的两个字节是name_index, 这是一个指向常量池的索引, 它描述的是当前方法的方法名。 这个索引指向常量池中的一个CONSTANT_Utf8_info数据项。 这个CONSTANT_Utf8_info数据项中存放的字符串就是当前方法的方法名。
(3)descriptor_index
- package com.jg.zhang;
- public class Programer extends Person{
- private Computer computer;
- public Programer(Computer computer){
- this.computer = computer;
- }
- public void doWork(){
- computer.calculate();
- }
- }
反编译之后, 常量池中会有如下信息(这里省略了大部分无关信息):
- Constant pool:
- .........
- #7 = Utf8 <init>
- #8 = Utf8 (Lcom/jg/zhang/Computer;)V
- .........
- #12 = Utf8 ()V
- .........
- #19 = Utf8 doWork
- {
- .........
- public com.jg.zhang.Programer(com.jg.zhang.Computer);
- flags: ACC_PUBLIC
- .........
- public void doWork();
- flags: ACC_PUBLIC
- .........
- }
由反编译结果可以看出, 该类中定义了两个方法, 其中一个是构造方法, 一个是doWork方法, 且这两个方法都是public的。 这两个方法的描述信息都存放在常量池。 其中第7项的CONSTANT_Utf8_info为构造方法的方法名, 第8项的CONSTANT_Utf8_info为构造方法的方法描述符, 第19项的CONSTANT_Utf8_info为doWork方法的方法名, 第12项的CONSTANT_Utf8_info为doWork方法的方法描述符。
总结
以上是关于 深入理解Java Class文件格式的主要内容,如果未能解决你的问题,请参考以下文章