Java字节码(.class文件)格式详解(一) (三)

2014-11-24 02:33:29 · 作者: · 浏览: 2
必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口的直接父类。只有Object类才没有直接父类,此时该索引值为0。并且父类不能是final类型。接口的父类都是Object类。

2.7 interfaces

interfaces数组记录所有当前类或接口直接实现的接口。interfaces数组中的每项值都是一个指向constant pool的索引值,这些值必须是CONSTANT_Class_info类型。数组中接口的顺序和源代码中接口定义的顺序相同。

2.8 fields

fields数组记录了类或接口中的所有字段,包括实例字段和静态字段,但不包含父类或父接口中定义的字段。fields数组中每项都是field_info类型值,它描述了字段的详细信息,如名称、描述符、字段中的attribute等。

field_info

type

descriptor

remark

u2

access_flags

记录字段的访问权限。见2.8.1

u2

name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定字段的名称。

u2

descriptor_index

constant_pool中的索引,CONSTANT_Utf8_info类型,指定字段的描述符(见附录C)。

u2

attributes_count

attributes包含的项目数。

attribute_info

attributes[attributes_count]

字段中包含的Attribute集合。见2.8.2-2.8.7

注:fields中的项目和CONSTANT_Fieldref_info中的项目部分信息是相同的,他们主要的区别是CONSTANT_Fieldref_info中的项目不仅包含了类或接口中定义的字段,还包括在字节码中使用到的字段信息。不过这里很奇怪,为什么field_info结构中不把name_index和descriptor_index合并成fieldref_index,这样的class文件不是更加紧凑吗??不知道这是sun因为某些原因故意这样设计还是这是他们的失误??

2.8.1 字段访问权限

字段的访问权限

Flag Name

Value

Remarks

ACC_PUBLIC

0x0001

pubilc,包外可访问。

ACC_PRIVATE

0x0002

private,只可在类内访问。

ACC_PROTECTED

0x0004

protected,类内和子类中可访问。

ACC_STATIC

0x0008

static,静态。

ACC_FINAL

0x0010

final,常量。

ACC_VOILATIE

0x0040

volatile,直接读写内存,不可被缓存。不可和ACC_FINAL一起使用。

ACC_TRANSIENT

0x0080

transient,在序列化中被忽略的字段。

ACC_SYNTHETIC

0x1000

synthetic,由编译器产生,不存在于源代码中。

ACC_ENUM

0x4000

enum,枚举类型字段

注:接口中的字段必须同时设置:ACC_PUBLIC、ACC_STATIC、ACC_FINAL

2.8.2 ConstantValue Attribute JVM识别)

ConstantValue Attribute

type

descriptor

remark

u2

attribute_name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute的名称(“ConstantValue”)。

u4

attribute_length

该Attribute内容的字节长度(固定值:2)

u2

constant_value_index

constant_pool中的索引,

CONSTANT_Integer_info(int,boolean,char、short、byte)、

CONSTANT_Float_info(float)、

Constant_Double_info(double)、

CONSTANT_Long_info(long)

CONSTANT_String_info(String)类型

每个常量字段(final,静态常量或实例常量)都包含有且仅有一个ConstantValue Attribute。ConstantValue Attribute结构用于存储一个字段的常量值。

对一个静态常量字段,该常量值会在类或接口被初始化之前,由JVM负责赋给他们,即它在任何静态字段之前被赋值。

对一个非静态常量字段,该值会被虚拟机忽略,它的赋值由生成的实例初始化函数()实现。如类:

classA {

publicstaticfinalintfa= 10;

publicfinalintfa2= 30;

privatestaticintsa= 20;

static{

sa= 30;

}

}

生成的字节码如下:

// Compiled from Test.java (version 1.6 : 50.0, super bit)

class org.levin.insidejvm.miscs.staticinit.A {

public static final int fa = 10;

public final int fa2 = 30;

private static int sa;

static {};

0 bipush 20

2 putstatic org.levin.insidejvm.miscs.staticinit.A.sa : int [16]

5 bipush 30

7 putstatic org.levin.insidejvm.miscs.staticinit.A.sa : int [16]

10 return

public A();

0 aload_0 [this]

1 invokespecial java.lang.Object() [21]

4 aload_0 [this]

5 bipush 30

7 putfield org.levin.insidejvm.miscs.staticinit.A.fa2 : int [23]

10 return

作者“上善若水”