class文件结构-之一


从上图中可以看到,一个 Java 类文件大致可以归为 10 个项:

  • Magic:该 项存放了一个 Java 类文件的魔数(magic number)和版本信息。一个 Java 类文件的前 4 个字节被称为它的魔数。每个正确的 Java 类文件都是以 0xCAFEBABE 开头的,这样保证了 Java 虚拟机能很轻松的分辨出 Java 文件和非 Java 文件。
  • Version:该项存放了 Java 类文件的版本信息,它对于一个 Java 文件具有重要的意义。因为 Java 技术一直在发展,所以类文件的格式也处在不断变化之中。类文件的版本信息让虚拟机知道如何去读取并处理该类文件。
  • Constant Pool:该 项存放了类中各种文字字符串、类名、方法名和接口名称、final 变量以及对外部类的引用信息等常量。虚拟机必须为每一个被装载的类维护一个常量池,常量池中存储了相应类型所用到的所有类型、字段和方法的符号引用,因此 它在 Java 的动态链接中起到了核心的作用。常量池的大小平均占到了整个类大小的 60% 左右。
  • Access_flag:该项指明了该文件中定义的是类还是接口(一个 class 文件中只能有一个类或接口),同时还指名了类或接口的访问标志,如 public,private, abstract 等信息。
  • This Class:指向表示该类全限定名称的字符串常量的指针。
  • Super Class:指向表示父类全限定名称的字符串常量的指针。
  • Interfaces:一个指针数组,存放了该类或父类实现的所有接口名称的字符串常量的指针。以上三项所指向的常量,特别是前两项,在我们用 ASM 从已有类派生新类时一般需要修改:将类名称改为子类名称;将父类改为派生前的类名称;如果有必要,增加新的实现接口。
  • Fields:该项对类或接口中声明的字段进行了细致的描述。需要注意的是,fields 列表中仅列出了本类或接口中的字段,并不包括从超类和父接口继承而来的字段。
  • Methods:该 项对类或接口中声明的方法进行了细致的描述。例如方法的名称、参数和返回值类型等。需要注意的是,methods 列表里仅存放了本类或本接口中的方法,并不包括从超类和父接口继承而来的方法。使用 ASM 进行 AOP 编程,通常是通过调整 Method 中的指令来实现的。
  • Class attributes:该项存放了在该文件中类或接口所定义的属性的基本信息。

ClassFile {

      u4 magic; // 必须为: 0xCAFEBABE
      u2 minor_version;
      u2 major_version; //CLASS文件结构主次版本号 JAVA2支持45.0-46.0
      u2 constant_pool_count; //记录常量信息
      cp_info constant_pool[constant_pool_count-1]; //计数从1开始
      u2 access_flags; //class/interface访问权限
      u2 this_class; //指向constant_poll中的有效索引值
      u2 super_class; //0或指向constant_poll中的有效索引值,对于interface必须为非0
      u2 interfaces_count; //superinterfaces的个数
      u2 interfaces[interfaces_count]; //计数[0,count-1) 对应constant_pool中的一个索引值
      u2 fields_count;
      field_info fields[fields_count]; //主要用于记录class及实例中的变量
      u2 methods_count;
      method_info methods[methods_count];
      u2 attributes_count;
      attribute_info attributes[attributes_count];
}

cp_info {
      u1 tag;
      u1 info[];
}
tag 意义如下:
CONSTANT_Class                7    
CONSTANT_Fieldref             9  
CONSTANT_Methodref            10  
CONSTANT_InterfaceMethodref   11  
CONSTANT_String               8  
CONSTANT_Integer              3  
CONSTANT_Float                4  
CONSTANT_Long                 5  
CONSTANT_Double               6  
CONSTANT_NameAndType          12  
CONSTANT_Utf8                 1 

此时cp_info分别对应结构变化为

1. CONSTANT_Class 
        CONSTANT_Class_info {
                u1 tag;
                u2 name_index;
        }
        
        2. CONSTANT_Fieldref
          CONSTANT_Fieldref_info {
                    u1 tag;
                    u2 class_index;  //constant_pool的索引,对应CONSTANT_Class_info 
                    u2 name_and_type_index;//constant_pool的索引,对应CONSTANT_NameAndType_info 
          }

        3. CONSTANT_Methodref
           CONSTANT_Methodref_info {
                    u1 tag;
                    u2 class_index;
                    u2 name_and_type_index;
           }

        4. CONSTANT_InterfaceMethodref
           CONSTANT_InterfaceMethodref_info {
                    u1 tag;
                    u2 class_index;
                    u2 name_and_type_index;
           }

        5. CONSTANT_String
           CONSTANT_String_info {
                    u1 tag;
                    u2 string_index;
            }

        6. CONSTANT_Integer
            CONSTANT_Integer_info {
                    u1 tag;
                    u4 bytes;
            }
   

        7. CONSTANT_Float
           CONSTANT_Float_info {
                    u1 tag;
                    u4 bytes;
           }

        8. CONSTANT_Long
            CONSTANT_Long_info {
                    u1 tag;
                    u4 high_bytes;
                    u4 low_bytes;
             }
   
        9. CONSTANT_Double
           CONSTANT_Double_info {
                    u1 tag;
                    u4 high_bytes;
                    u4 low_bytes
           }

        10.CONSTANT_NameAndType
            CONSTANT_NameAndType_info {
                    u1 tag;
                    u2 name_index;
                    u2 descriptor_index;
            }

        11.CONSTANT_Utf8
            CONSTANT_Utf8_info {
                    u1 tag;
                    u2 length;
                    u1 bytes[length];
            }

access_flags意义如下:

ACC_PUBLIC     0x0001  
ACC_FINAL      0x0010  
ACC_SUPER      0x0020  
ACC_INTERFACE  0x0200  
ACC_ABSTRACT   0x0400  
如果是interface那么必须置ACC_INTERFACE,如果没有置ACC_INTERFACE则定义的是一个类而非接口。
如果设置了ACC_INTERFACE,那么ACC_ABSTRACT位也必须被设置,当然也可以设置ACC_PUBLIC。
ACC_SUPER用以表明invokespecial语义,Sun公司老的JAVA编译器没有设置ACC_SUPER,并且老的JVM忽略ACC_SUPER位,但新的编译器应该实现invokespecial语义。
其他未指明的位保留将来使用,并且编译器应当将其置为0,同时Java虚拟机应当忽略他们。

this_class

constant_pool中的索引值,指向的元素的cp_info等价为CONSTANT_Class_info

CONSTANT_Class_info {
      u1 tag; //必须为CONSTANT_Class (7)
      u2 name_index; //为指向constant_pool中的一个索引值
}

name_index :指向的元素的cp_info等价为CONSTANT_Utf8_info

CONSTANT_Utf8_info {
      u1 tag; //必须为CONSTANT_Utf8 (1)
      u2 length;
      u1 bytes[length]; //Utf8编码的字符串
}


field_info{
      u2 access_flags; //访问控制权
      u2 name_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。
      u2 descriptor_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。
      u2 attributes_count;
      attribute_info attributes[attributes_count]; //attribute_info将在mothods后描述。
}
field_info中access_flages意义如下:
ACC_PUBLIC 0x0001
ACC_PRIVATE 0x0002
ACC_PROTECTED 0x0004
ACC_STATIC 0x0008
ACC_FINAL 0x0010
ACC_VOLATILE 0x0040
ACC_TRANSIENT 0x0080
其中很显然不能同时为ACC_FINAL和ACC_VOLATILE ;且前三项是互斥的。
interface必须置ACC_PUBLIC, ACC_STATIC,ACC_FINAL位,且不能置其他位。
其他未指明的位保留将来使用,并且编译器应当将其置为0,同时Java虚拟机应当忽略他们。

method_info {
      u2 access_flags;
      u2 name_index; //指向constant_pool的入口,对应为CONSTANT_Utf8_info
      u2 descriptor_index; //指向constant_pool的入口,对应为CONSTANT_Utf8_info
      u2 attributes_count;
      attribute_info attributes[attributes_count];
      //此处只能出现Code、Exceptions、Synthetic、Deprecated四种类型的属性
}

access_flags访问权描述如下:

ACC_PUBLIC        0x0001 
ACC_PRIVATE       0x0002 
ACC_PROTECTED     0x0004 
ACC_STATIC        0x0008 
ACC_FINAL         0x0010 
ACC_SYNCHRONIZED  0x0020 
ACC_NATIVE        0x0100 
ACC_ABSTRACT      0x0400 
ACC_STRICT        0x0800  

attribute_info {

      u2 attribute_name_index; //constant_pool中的索引,对应于CONSTANT_Utf8_info描述。
      u4 attribute_length;
      u1 info[attribute_length];
}
现在已经预定义的属性有:
1. SourceFile : attribute_info被替代为:
SourceFile_attribute {
      u2 attribute_name_index;
      u4 attribute_length;
      u2 sourcefile_index; //指向constant_pool中的一个CONSTANT_Utf8_info 结构。
}
2. ConstantValue : attribute_info被替代为:
ConstantValue_attribute {
      u2 attribute_name_index;
      u4 attribute_length; //必须为2
      u2 constantvalue_index;
}
对于constantvalue_index意义如下:
long CONSTANT_Long
float CONSTANT_Float
double CONSTANT_Double
int, short, char, byte, boolean CONSTANT_Integer
String CONSTANT_String
ConstantValue用于field_info 中,用于描述一个static常量,且此时field_info的access_flags应为ACC_STATIC

3. Code : attribute_info被替代为:

Code_attribute {
      u2 attribute_name_index;
      u4 attribute_length;
      u2 max_stack; //执行此函数时可用的栈的最大深度
      u2 max_locals; //执行此函数可用到的最大本地变量数目,包括参数。
      // 注意:一个long/double相当于2个变量数目.
      u4 code_length; //本函数用到的代码长度。
      u1 code[code_length]; //实现本函数的真正字节码
      u2 exception_table_length;
      { u2 start_pc;
      u2 end_pc; //捕获违例时执行代码数组中的[start_pc, end_pc)部分
      u2 handler_pc; //现在还不大明白他是干嘛的!!
      u2 catch_type; //指向constant_pool的索引,对应CONSTANT_Class_info
      }exception_table[exception_table_length];
      u2 attributes_count;
      attribute_info attributes[attributes_count];
}
CONSTANT_Class_info {
      u1 tag; //必须为CONSTANT_Class (7)
      u2 name_index; //不用我再说了吧?
}
Code属性用于method_info结构中。
4. Exceptions : attribute_info被替代为:
Exceptions_attribute {
      u2 attribute_name_index;
      u4 attribute_length;
      u2 number_of_exceptions;
      u2 exception_index_table[number_of_exceptions];
}
5. InnerClasses : attribute_info被替代为:
InnerClasses_attribute {
      u2 attribute_name_index;
      u4 attribute_length;
      u2 number_of_classes;

      {      u2 inner_class_info_index;

              u2 outer_class_info_index;
              u2 inner_name_index;
              u2 inner_class_access_flags;
      } classes[number_of_classes];
}
6. Synthetic : attribute_info被替代为:
Synthetic_attribute {
      u2 attribute_name_index; //不用废话了吧?
      u4 attribute_length; //必须为0
}
Synthetic用在 field_info、 method_info 中,一个没有出现在源程序中的变量必须使用Synthetic标记。
7. LineNumberTable : attribute_info被替代为:
LineNumberTable_attribute {
      u2 attribute_name_index;
      u4 attribute_length;
      u2 line_number_table_length;
      {      u2 start_pc; //代码数组中的开始处
             u2 line_number; //源文件中的行号(对于每一非空行都有这么一项)
      } line_number_table[line_number_table_length];
}
LineNumberTable用于Code属性中,通常用于调试。
8. LocalVariableTable : attribute_info被替代为:
LocalVariableTable_attribute {
      u2 attribute_name_index;
      u4 attribute_length;
      u2 local_variable_table_length;
      {      u2 start_pc;
              u2 length; //当解释到代码数组的[start_pc,start_pc+length]时变量必须被赋值
              u2 name_index;
              u2 descriptor_index;
              u2 index; //到本地变量数组的一个索引
      } local_variable_table[local_variable_table_length];
}
9. Deprecated : attribute_info被替代为:
Deprecated_attribute {
      u2 attribute_name_index;
      u4 attribute_length; //必须为0
}
当然你也可以定义自己的属性,但要你自己的编译器和虚拟机实现。JVM将忽略自己不认可的属性。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值