Java Class文件

类文件(.class文件扩展名)是包含Java字节码 ByteCode的文件,可以在Java虚拟机上执行,每个类文件包含了一个类,接口或者模块(Java 9)的定义

Java程序(.java 文件)可以通过 Java compiler 生成字节码文件,其他基于JVM的语言也都可以通过自己的编译器生成字节码文件,例如Scala,Groovy等

JVM是与平台无关的,类文件可以在多个平台上执行,这使得相应的语言也与平台无关。

Class类文件的结构

类文件由8位字节流组成, 多字节数据使用big-endian的方式存储
类文件是按照ClassFile结构生成的字节流,字段连续存储,没有任何填充或对齐。
Class文件格式采是用类C的结构符号表示的伪结构存储数据,有两种数据类型,无符号数(u1,u2,u4,u8)和表(*_info)

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 文件中涉及类/方法等名称和描述

名称

Binary Class and Interface Names
全限定名称,也叫二进制名称
例如 Thread正常的二进制名称为 java.lang.Thread ,但是因为一些历史原因,内部格式下,.被替换成了正斜线/,使用CONSTANT_Utf8_info结构(即Utf8编码的字符串常量)表示其为java/lang/Thread

Unqualified Names
非限定名称,即简单名称,例如Thread

描述符

描述符是表示字段或方法类型(type)的字符串,使用modified UTF-8(UTF-8缩略编码)

Field Descriptors
基本数据类型用一个大写字符表示,int对应 I
对象类型使用一个L加上全限定,末尾加上分号;表示,Object对应Ljava/lang/Object;
数组每个维度使用一个前置[表示,double[][][]对应[[[D

Interpretation of field descriptors

Method Descriptors
由零个或者多个参数描述符,加上一个返回值描述符组成
( {ParameterDescriptor} ) ReturnDescriptor

Object m(int i, double d, Thread t) {...}
对应
(IDLjava/lang/Thread;)Ljava/lang/Object;


magic & version

魔数magic number :识别类文件格式,值为0xCAFEBABE
版本号:M.m(主版本号M,副版本号 m)
major version从45开始的,每个大版本号向上加1
JDk1.1.* 支持45.0 到 45.65535
JDk1.8.* 支持45.0 到 52.65535
JDk1.k.* 支持主版本号45.0 到 44+k.0 (k>=2)

常量池

常量池数目constant_pool_count,数目等于常量表的条目数+1
常量池constant_pool是一张表,结构化的表示各种字符串常量,类和接口名称,字段名称等,表索引为1到constant_pool_count - 1

它的用处在于:Java虚拟机指令不依赖于运行时的布局,编译时没有链接这一步,所以指令引用的是constant_pool表中的符号信息

通用结构

cp_info {
    u1 tag;
    u1 info[];
}

表中的每一项都以一个1byte的标志位开头,指明该项的常量类型,之后是紧跟相应的内容,每种类型都有自己的结构

Constant pool tags

CONSTANT_Class_info 结构

CONSTANT_Class_info {
      u1 tag;
      u2 name_index;
}

tag :CONSTANT_Class (7)
name_index:是constant_pool中有效的索引,其对应的位置必定是一个CONSTANT_Utf8_info结构,表示类或接口的名称

CONSTANT_Utf8_info 结构

CONSTANT_Utf8_info {
      u1 tag;
      u2 length;
      u1 bytes[length];
}

tag :CONSTANT_Utf8 (1)
length:长度,限定了最大长度为65535
bytes[]:Modified UTF-8形式的字符串

CONSTANT_Fieldref_info 结构
用于类加载过程中的解析

CONSTANT_Fieldref_info {
      u1 tag;
      u2 class_index;
      u2 name_and_type_index;
}

CONSTANT_Fieldref_info, CONSTANT_Methodref_info, CONSTANT_InterfaceMethodref_info三种常量结构相似, tag作为标识,class_index指向相应的类或接口类型信息的常量,name_and_type_index指向CONSTANT_NameAndType_info结构,表示方法或字段的名称和描述符

访问标志 access_flags

类或接口的访问权限和属性的标志掩码

Class access and property modifiers

自身和父类的信息 this_class / super_class

u2类型,指向CONSTANT_Class_info的索引,父类的索引可以为0(java.lang.Object没有父类),可以获取对应的类名称

接口信息 interfaces_count / interfaces[]

描述了该类扩展的接口信息,interfaces[i] 都是constant_pool表中的CONSTANT_Class_info的索引, 0 ≤ i < interfaces_count,接口的顺序按照源文件中的实现从左向右排列

字段表

fields_countfields表中field_info结构的数目
field_info结构代表了类或接口中所有的字段(类变量class variables(静态变量),实例变量instance variables(类实例中包含的变量)),但是不包含他们的父类或者父接口继承来的字段

field_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}
Field access and property flags

name_index:指向CONSTANT_Utf8_info结构的索引,表示一个有效的非限定名称
descriptor_index:指向CONSTANT_Utf8_info结构的索引,表示字段的描述符

之后是属性信息,存储一些额外的信息,例如对于final static int m = 1,有ConstantValue属性,包含静态变量的赋值信息。

方法表

method_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

同字段表类似,访问标识有部分不同


Method access and property flags

方法中的Java代码,经过编译器,编译成字节码格式之后,存放在方法的属性表内的Code属性内
方法表中可能会有编译器自己添加的方法,例如<init><clinit>

属性表

ClassFile, field_info, method_info, and Code_attribute 结构中,都含有属性
Java 9共有26种预定义的属性

Predefined class file attributes

每个属性的名称用CONSTANT_Utf8_info表示,属性的结构如下

attribute_info {
    u2 attribute_name_index;
    u4 attribute_length;
    u1 info[attribute_length];
}

Code属性

是可变长度的属性,包含了一个方法的JVM指令和辅助信息
nativeabstract类没有Code属性

//Code 属性的结构
Code_attribute {
    u2 attribute_name_index; //对应一个`CONSTANT_Utf8_info `索引,内容是Code
    u4 attribute_length;
    u2 max_stack; //operand stack 操作数栈的最大深度
    u2 max_locals;//局部变量数组的长度
    u4 code_length; //长度小于65536
    u1 code[code_length];//字节码指令
    u2 exception_table_length;
    {   u2 start_pc;
        u2 end_pc; //在code数组中的起点和终点[start_pa, end_pc)
        u2 handler_pc; //异常处理对应的字节码起始位置
        u2 catch_type;// 是常量池中 CONSTANT_Class_info的索引,表示捕获的异常类型,为0则处理任何异常 
    } exception_table[exception_table_length];//异常表
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

Exception属性

声明所有的受查异常(checked exception,不是派生于ErrorRuntimeException的其他所有异常)

Exceptions_attribute {
    u2 attribute_name_index; //索引指向`CONSTANT_Utf8_info `表示"Exceptions"
    u4 attribute_length;
    u2 number_of_exceptions;
    u2 exception_index_table[number_of_exceptions]; //索引指向`CONSTANT_Class_info`,表示受查异常的类型
}

LineNumberTable

出现在Code属性的attributes表中,显示code字节码和相应java源文件的行号
用于调试,以及抛出异常时,显示出错的行号

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];
}

LocalVariableTypeTable

局部变量表,出现在Code属性的attributes表中,用来在调试过程中描述局部变量的具体类型

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 signature_index;//签名信息,和描述符类似,保留了泛型类型
        u2 index;//局部变量在当前栈帧局部变量表中的位置索引
    } local_variable_table[local_variable_table_length];
}
函数示例

SourceFile

记录源码文件的名称

Signature

Signature_attribute {
    u2 attribute_name_index; // "Signature"
    u4 attribute_length;  //必定是2
    u2 signature_index; //对应CONSTANT_Utf8_info,表示类,接口,构造器,方法,字段的签名
}

Java字节码的方法的特征签名,包含返回值和受查异常表(详细信息,参考jvms9 4.7.9.1)
[TypeParameters] ( {JavaTypeSignature} ) Result {ThrowsSignature}

InnerClass

记录内部类和宿主类之间的关联

InnerClasses_attribute {
    u2 attribute_name_index; 
    u4 attribute_length;
    u2 number_of_classes;
    {   u2 inner_class_info_index;//内部类或接口信息CONSTANT_Class_info
        u2 outer_class_info_index;//外部类或接口信息CONSTANT_Class_info
        u2 inner_name_index;//内部类的名称CONSTANT_Class_info,匿名内部类名称为0
        u2 inner_class_access_flags;
    } classes[number_of_classes];
}
Nested class access and property flags

ConstantValue

静态变量相关的一个定长属性

ConstantValue_attribute {
      u2 attribute_name_index;
      u4 attribute_length;
      u2 constantvalue_index;
}
常量池中对应字段的类型

javap

反编译Class文件,没有选项时输出包,类里的protected和public字段和方法

用法:javap [options] classfile

  • -verbose 打印细节,可以查看常量表,栈大小,各方法的 locals 及 args 数等
  • -p -private 显示所有的类和成员
  • -c 输出类中各方法的 Java 字节码的指令
  • -s signatures,输出内部类型签名

Reference:
Java Language and Virtual Machine Specifications
The Java® Virtual Machine Specification Java SE 9 Edition

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容

  • Java代码必须要被编译成class文件后,虚拟机才能够加载运行,要搞清楚Java的类加载机制,首先必须要理解Cl...
    云飞扬1阅读 9,264评论 2 61
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,633评论 18 139
  • 转自 http://blog.csdn.net/wen7280/article/details/53856790 ...
    云狗狗狗狗狗阅读 960评论 0 1
  • “《酥油》 是对我们每个人内在力量的最好诠释。其实梦想、爱与勇气从来都贮藏在我们的内心,从未远去。也许只要一...
    流年微凉凉阅读 518评论 8 5