Class类文件的结构

概念:Class文件是一组以8位字节为基础单位的二进制流
按顺序整齐排列
没有任何分隔符,内容全部是运行时的必要数据,没有空隙存在

  • 排序方式:高位在前
    Big-Endian:最高字节在地址最低位,最低字节在地址最高位
    Little-Endian:相反

  • 储存方式:类似于C语言结构体的伪结构来储存只有两种数据类型
    无符号:属于基本数据类型

    u1:1个字节
    u2:2个字节
    u4:4个字节
    u8:8个字节

  • 表:多个无符号数或其他表作为数据项构成的复合数据类型
    以"_info"结尾
    描述有层次关系的复合结构数据
    整个Class文件本质上就是一张表

  • 魔数: 魔数
    每个Class文件的头4个字节
    确定这个文件是不是一个能被虚拟机接收的Class文件
    Java中的值为:0xCAFEBABE->咖啡宝贝

  • Class文件版本:
    紧接着的4个字节
    第5个和第6个:次版本号(Minor Version)
    第7个和第8个:主版本号(Major Version)
    满足向下兼容,即高版本兼容低版本的Class文件,反之不行

  • 常量池:
    紧接着版本号
    Class文件中的资源仓库,占用空间最大
    常量池容量计数值(constant_pool_count),从1开始而不是从0开始计数
    常量池中常量数量不确定,需要一个计数是u2类型的数据
    设计者将从0位做特殊考虑,特殊情况下,有些指向常量池的索引数据要表达"不引用任何常量池项目"的意义
    常量池容量(偏移地址:0x00000008),十进制22,表示常量池中有21项常量,索引1~21
    主要存放数据类型字面量(Literal):
    如文本字符串,final常量等符号引用(Symbolic References)
    类和接口的全限定名
    字段的名称和描述符
    方法的名称和描述符

  • 14种常量池的每个常量表:
    constant_utf8_info 1 utf-8
    u1 tag 1 标志位//用于区分常量类型
    u2 length 1 utf-8真正的字符串内容
    constant_integer_info 3 整型
    constant_float_info 4 浮点型
    constant_long_info 5 长整型
    constant_double_info 6 双精度
    constant_class_info 7 类或接口的符号引用
    constant_string_info 8 字符串型
    constant_fieldref_info 9 字段符号引用
    constant_methodref_info 10 类中方法的符号引用
    constant_interfaceMethodref_info 11 接口中符号引用
    constant_NameAndType_info 12 字段或方法的部分符号引用
    constant_MethodHandle_info 15 方法句柄
    constant_MethodType_info 16 表示方法类型
    constant_InvokeDynamic_info 18 动态方法调用点

  • 访问标识:紧接着常量池,两个字节,总共16位,当前只定义了其中8个,未使用一律使用0
    ACC_PUBLIC 0x0001 public
    ACC_FINAL 0x0010 final
    ACC_SUPER 0x0020 invokespecial
    ACC_INTERFACE 0x0400 abstract
    ACC_SYNTHETIC 0x1000 并非由用户代码产生
    ACC_ANNOTATION 0x2000 注解
    ACC_ENUM 0x4000 枚举

  • 类索引(this_class),父类索引(super_class)与接口索引(interfaces)集合(u2类型数据)
    紧接着访问标志
    u2类型(this_class,super_class)u2类型集合(interfaces)
    各索引的含义:
    这三项数据来确定类的继承关系
    类索引(this_class)用来确定类全限定名
    父类索引(super_class)确定父类的全限定名
    接口索引描述类实现的接口,按从左到右的顺序排列
    父类索引(super_class)除了java.lang.Object外,其他类都不为0

  • 字段集合(field_info)
    描述接口/类中声明的变量包含:
    作用域(public private protected)
    实例变量还是类变量(static)
    可变性(final)
    并发可见性(volatile)
    序列化(transient)
    字段数据类型
    字段名称
    全限定名,相当于类的全路径,只是把.换成/,如java/lang/Object
    简单名称,方法或属性名的简写,如inc()方法和m属性,则简单名称为inc和m
    描述符:
    描述字段数据类型,方法的参数列表和返回值
    基本数据类型和void都用一个大写字母来表示,对象类型用L加全限定名来表示
    标识名: B(byte), C(char), D(double), F(float), I(int), J(long), S(short), Z(boolean), V(void), L(对象类型)
    数组描述符:
    一维数组:String[]–>[Ljava/lang/String
    二维数组:String[][]–>[[Ljava/lang/String
    方法描述符:
    参数列表在前,返回值在后的顺序参数列表放在()内,如:void inc()描述为()V
    int indexOf(char[] source,int sourceOffset, int sourceCount,char[] target, int targetOffset, int targetCount,int fromIndex)描述为 ([CII[CII)I

  • 方法表集合:
    包含:
    访问标志(access_flags)
    名称索引(name_index)
    描述符索引(descriptor_index)
    属性表集合(attributes)
    方法表集合中没有方法里面的代码,Java代码存在属性表中名为"Code"的属性里面

  • 重写和重载的原理:
    Override:如果子类未重写父类方法,方法表集合中就不会出现来自父类的方法信息,但是有可能出现编译器自动添加方法,如构造方法
    OverLoad:重载方法,保证和原方法具有相同的简单名称之外,还必须拥有一个与原方法不同的特征签名,返回值没有包含在特征签名中,因此无法依靠返回值确定方法重载,在Class文件中,如果一个方法具有相同的名称和特征签名,但返回值不同,可以包含在同一个Class文件中
    特征签名:一个方法中各个参数在常量池中的字段符号引用的集合

  • 属性表集合:
    描述某些场景的专有信息, 没有太多顺序长度内容的限制
    虚拟机规范预定义的属性
    属性名及使用位置及含义:
    Code 方法表 Java代码编译成的字节码文件
    ConstantValue 字段表 final关键字定义的常量
    Deprecated 类方法表字段表 被声明为deprecated的方法和字段
    Exceptions 方法表 方法抛出异常
    EnclosingMethod 类文件 一个类为匿名类,局部类拥有此属性,用于标识这个类所在的外围方法
    InnerClass 类文件 内部类列表
    LineNumber Code属性 Java源代码的行号与字节码指令的对应关系
    LocalVariableTable Code属性 方法的局部变量描述
    StackMapTable Code属性 JDK1.6新增,类型检查,处理目标方法的局部变量和操作数栈所需的类型是否匹配
    Signature 类方法表字段表 JDK1.5新增,支持泛型情况下方法签名
    SourceFile 类文件 记录源文件名
    SourceDebugExtension 类文件 JDK1.6增,用于存储额外的调试信息
    Synthetic 类方法表字段表 标识方法或字段为编译器自动生成的
    LocalVariableTypeTable JDK1.5新增,使用特征签名代替描述符
    RuntimeVisibleAnnotations 类方法表字段表 JDK1.5新增,为动态注解提供支持,指明哪些注解是运行可见
    BootstrapMethods JDK1.7新增,用于保存invokedynamic指令引用的引导方法限定符
    Code属性:
    Java编译器处理后的字节码指令存储在Code属性内; Code属性出现在方法表的属性集合中; 并非所有的方法都必须存在这个属性
    类型 名称 数量
    u2 attribute_name_index(指向CONSTANT_UF8_info类型常量的索引) 1
    u4 attribute_length(属性值长度) 1
    u2 max_stack(操作数占最大深度,在执行操作数栈时都不会超过这个最大深度,JVM在需要的时候根据此值分配栈帧中的操作栈深度) 1
    u2 max_locals(局部变量表所需的储存空间根据Slot//局部变量最小单位,计算) 1
    u4 code_length(编译后的字节码指令) 1
    u1 code(编译后的字节码指令流) code_length
    u2 exception_table_length(异常表长度) 1
    exception_info exception_table(异常表内容) exception_table_length
    u2 attributes_counts(属性数量) 1
    attribute_info attributes(属性内容) attributes_counts
    Code属性是Class文件中最重要的一个属性,如果把Class文件分解为Code和Metadata,Code可以描述为代码,Metadata解释其他数据
    attribute_name_index:固定为"Code",表示该属性的名字
    attribute_length:由于属性名和属性长度一共6个字节(u2+u4),所以属性值的长度就是整个属性表的长度减去这两个属性
    max_stack:在方法执行的任意时刻,操作数栈都不会超过这个长度,虚拟机运行时根据这个值分配栈帧中的操作栈深度
    max_locals:单位Solt,是虚拟机为局部变量分配内存的最小单位; 注:Slot重用,并不是方法中使用多少局部变量,就把这些局部变量所占的Slot之和作为max_locals.当代码执行超出一个局部变量的作用域时,这个局部变量所占的Slot可以被其他局部变量所使用
    code_length:code_length代表编译后的字节码长度,code是储存字节码指令的一系列字节流
    exception_table_length:不是必须存在的

  • this关键字:
    任何实例方法中都能通过this访问所属对象
    javac编译器编译的时候把对this关键字访问转变为一个对普通方法参数的访问然后在虚拟机调用实例方法时自动传入此参数,所以在实例方法的局部变量表中至少会存在一个指向当前对象的实例局部变量
    局部变量表中也会预留出第一个Slot位来存放对象实例的引用,方法参数值从1开始计算,这个处理只会对实例方法有效,对静态方法无效

  • Exceptions属性(下列方法将会抛出受查异常,方法描述时在throws关键字后面列举的异常)
    u2 attribute_name_index 1
    u4 attribute_length 1
    u2 number_of_exceptions 1
    u2 exception_index_table number_of_exceptions

  • LineNumberTable属性
    描述Java源码行号与字节码行号(字节码的偏移量)之间的对应关系不是运行时必须属性,但会默认生成到Class文件中
    可以在Javac中使用-g:none/lines来取消生成这项信息不生成该属性,抛出异常时,堆栈中部会显示出错的行号,并且在调试的时候,也无法按照源码来设置断点

  • LocalVariableTable属性
    描述栈帧中局部变量表中变量与Java源码中定义的变量之间的关系; 不是运行时必须属性,但会默认生成到Class文件中; 可以在Javac中使用-g:none/vars来取消或者要求生成该属性或不生成该属性; 当其他人引入该方法时,所有的参数名称都会丢失,IDE将会使用arg0,arg1之类的占位符代替原有的参数名,但对程序运行没有影响

  • SourceFile属性:
    记录生成Class文件的源码文件名称
    可选的属性
    可以在Javac中使用-g:none/source来关闭/生成这项信息
    不开启,内部类抛出异常的时候,堆栈不会显示出错代码所属文件名

  • ConstantValue属性:
    通知虚拟机自动为静态变量赋值
    如果是非静态变量,赋值在方法中
    静态:被final static修饰,并且是基本类型/String,就要生成ConstantValue来初始化; 否则一致在方法中初始化

  • InnerClass属性:
    记录内部类与宿主类之间的关联;如果定义内部类,编译器会为他及内部类生成InnerClass属性
    Synthetic属性:表示字段或方法不是由Java源代码直接生成的,而是由编译器添加
    其他属性不做介绍.很少使用

JVM字节码指令

一个字节长度,代表某种特定操作含义的数字(操作码Opcode)以及后面的0至多个代表此操作所需参数(操作数Operands)构成

  • JVM面向操作数栈,而非寄存器:
    优势:放弃操作数长度对齐,省略很多空格换行符
    缺点:导致解释执行字节码损失性能
  • 字节码与数据类型:
    i-int,l-long,s-short,b-byte,c-char,f-float,d-double,a-reference
    加载储存指令(用于将数据在栈帧中的局部变量表和操作数栈之间来回传输):
    将一个局部变量加载到操作栈: iload,iload_,…其他以此类推
    将一个数值从操作数栈存储到局部变量表: istore,istore_,…其他以此类推
    将一个常量加载到操作数
  • 栈: bipush,sipush,ldc,ldc_w,ldc2_w,aconst_null,iconst_ml,lconst_,fconst_,dconst_
    扩充局部变量表的访问索引:wide, 注:等,标示一组指令,如:iload_代表iload_0,iload_1…
  • 运算指令:
    用于对两个操作数栈上的值进行特定运算,并把结构重写存入操作数栈,指令如下:
    加法:iadd,ladd,fadd,dadd
    减法:isub,lsub,fsub,dsub
    乘法:imul,lmul,fmul,dmul
    除法:idiv,ldiv,fdiv,ddiv
    求余:irem,lrem,frem,drem
    取反:ineg,lneg,fneg,dneg
    位移:ishl,ishr,iushr,lshl,lshr,lushr
    按位或:ior,lor
    按位与:iand,land
    按位异或:ixor,lxor
    局部变量:iinc
    比较指令:dcmpg,dcmpl,fcmpg,fcmpl,lcmp
    注:byte,short,char,boolean,没有直接支持的算术指令,操作时使用int类型指令替换; 针对运算数出现操作溢出,JVM并不会抛出异常,只会返回结果NaN(null的意思)
  • 类型转换指令:
    将两种不同的数据类型进行互相转换,操作一般用于实现用户代码中的显式转换
    直接支持宽化类型转换,向上,小转大
    int->long,float,double等等
    处理窄化类型转换,必须显式使用转化指令
    i2b,i2c,i2s,l2i,f2i,f2l,d2i,d2l,d2f
  • 对象创建于访问指令:
    创建对象:new
    创建数组指令:newarray,anewarray,multianewarray
    访问类字段和实例字段指令:getfield,putfield,getstatic,putstatic
    把一个数组元素加载到操作数栈:baload,caload,saload,iaload,laload,faload,daload,aaload
    将一个操作数栈的值存储到数组元素当中:bastore,castore,sastore,iastore,fastore,dastore,aastore
    取数组长度:arraylength
    检查类实例类型:instanceof,checkcast
    操作数栈管理指令:
    将操作数栈的栈顶一个或两个元素出栈:pop,pop2
    复制栈顶一个或两个数值并将复制值或者双份的复制值重新压入栈顶:dup,dup2,dup_x1,dup2_x1,dup_x2,dup_x2,dup2_x2
    将栈最顶端的两个数值交换:swap
  • 控制转移指令:
    条件分支:ifeq,iflt,ifle,ifne,ifgt,ifge,ifnull,ifnonull,if_icmpeq,if_icmpne,if_icmplt,if_icmpgt,if_icmple,if_icmpge,if_acmpeq,if_acmpne
    复合条件分支:tableswitch,lookupswitch
    无条件分支:goto,goto_w,jsr,jsr_w,ret
  • 方法调用和返回:
    调用对象的实例方法:invokevirtual
    调用接口方法:invokeinsterface
    调用一些需要特殊处理的实例方法(实例初始化方法,私有方法,父类方法):invokespecial
    调用静态方法:invokestatic
    在运行时动态解析出调用点限定符引用的方法,并执行该方法:invokedynamic; 异常处理:athrow(throw)
  • 同步指令:
    JVM支持方法及同步和方法内部一段指令序列的同步,这两种同步结构都是使用Monitor来支持的
    方法级的同步是隐式的,无需通过字节码指令控制,它是现在方法调用和返回操作之中,JVM从方法常量池的方法表结构中ACC_SYNCHRONIZED访问标志得知一个方法是否声名为同步方法,当方法调用,调用指令将会检查方法的ACC_SYNCHRONIZED是否被设置,如果设置了,执行线程就要求持有Monitor,然后才能执行方法,当方法完成时释放Monitor
    注:编译器必须确保无论方法通过何种方式完成,方法中调用过得每条monitorenter指令都必须执行对应的monitorexit指令(无论方法正常/异常结束)

Java的Class类文件结构及基本字节码指令相关推荐

  1. c++byte数组和文件的相互转换_5分钟系列之Java类文件结构(三、字节码指令简介)...

    字节码指令简介1字节码与数据类型2加载和存储指令3运算指令4类型转换指令5对象创建与访问指令6操作数栈管理指令7 控制转移指令8方法调用和返回指令9异常处理指令10同步指令公有设计和私有实现Class ...

  2. JAVA类加载对字节码的处理_深入理解Java虚拟机(类文件结构+类加载机制+字节码执行引擎)...

    [本文版权归微信公众号"代码艺术"(ID:onblog)所有,若是转载请务必保留本段原创声明,违者必究.若是文章有不足之处,欢迎关注微信公众号私信与我进行交流!] 周志明的< ...

  3. java虚拟机编译_[四] java虚拟机JVM编译器编译代码简介 字节码指令实例 代码到底编译成了什么形式...

    前言简介 前文已经对虚拟机进行过了简单的介绍,并且也对class文件结构,以及字节码指令进行了详尽的说明 想要了解JVM的运行机制,以及如何优化你的代码,你还需要了解一下,java编译器到底是如何编译 ...

  4. JVM学习-字节码指令

    目录 1.入门 2 javap 工具 3 图解方法执行流程 3.1.原始 java 代码 3.2.编译后的字节码文件 3.3.常量池载入运行时常量池 3.4.方法字节码载入方法区 3.5.main 线 ...

  5. 你还在为怎么查看字节码指令而担忧吗?

    来自:烟雨星空 前言 我们平时编码过程中,可能很少去查看 Java 文件编译后的字节码指令.但是,不管你是因为对技术非常热爱,喜欢刨根问底,还是想在别人面前装X .我认为,都非常有必要了解一下常见的字 ...

  6. 深入理解Java虚拟机知乎_深入理解Java虚拟机(类文件结构)

    深入理解Java虚拟机(类文件结构) 欢迎关注微信公众号:BaronTalk,获取更多精彩好文! 之前在阅读 ASM 文档时,对于已编译类的结构.方法描述符.访问标志.ACC_PUBLIC.ACC_P ...

  7. 深入理解Java虚拟机(类文件结构)

    欢迎关注微信公众号:BaronTalk,获取更多精彩好文! 之前在阅读 ASM 文档时,对于已编译类的结构.方法描述符.访问标志.ACC_PUBLIC.ACC_PRIVATE.各种字节码指令等等许多概 ...

  8. 深入java虚拟机 class类文件结构

    平台无关性 Java是与平台无关的语言,这得益于Java源代码编译后生成的存储字节码的文件,即Class文件,以及Java虚拟机的实现.不仅使用Java编译器可以把Java代码编译成存储字节码的Cla ...

  9. class 类文件结构与字节码指令

    JVM执行子系统 一.Class 类文件结构 1.Java跨平台的基础 各种不同平台的虚拟机与所有平台都统一使用的程序存储格式--字节码(ByteCode)是构成平台无关性的基石,也是语言无关性的基础 ...

最新文章

  1. Virtio:针对 Linux 的 I/O 虚拟化框架
  2. Markovs Chains采样
  3. mis dss gis_MIS中的决策支持系统(DSS)
  4. 拦截方法并替换成自己的方法
  5. 细究STP根端口和指定端口的选举过程
  6. 微信小程序一键获取用户头像、昵称等基本信息
  7. linux操作系统(云服务器中的使用)
  8. IOS8 keyboardWillShow 在UIKeyboardWillShowNotification 调用两次 问题解决
  9. 推荐系统8——利用社交网络数据推荐
  10. 身体这些部位不舒服的时候,你知道意味着什么吗?
  11. WaitForSingleObject -- setevent 讲解与编程示例
  12. mel表达式_Maya Mel基础知识教程 了解运用Mel
  13. nohup 命令的使用
  14. windows8只能安装在C盘?分享win8安装过程中的注意事项!安装必读!
  15. 58同城笔试:后端开发编程题
  16. Danmo 的学习之路(HTML——CSS)
  17. python 处理Excel表格绘图方法
  18. DisplayFusion—多屏管理软件
  19. QA200RC 开发者套件配置虚拟机开发环境(PC端)
  20. 【合集】万字长文带你重温Elasticsearch ,这下完全懂了!

热门文章

  1. abap常用系统变量
  2. mysql中like % %模糊查询
  3. android预览界面编译出错,Android O预览findViewById编译错误
  4. 计算机二级python选择题题库_2018年计算机二级python题库精编(1)
  5. alsa 测试 linux_Electron 构建步骤 (Linux)
  6. android tcp socket框架_socket网络编程知识梳理,让你学会造轮子的能力
  7. Linker command failed with exit code 1(use -v to see invocation)
  8. linux grep 匹配空格_17 个案例,5 分钟简单搞定 Linux 正则表达式!
  9. matlab里数组的赋值,arrays – MATLAB结构赋值数组
  10. java微信web支付开发_微信支付java开发详细第三方支付功能开发之支付宝web端支...