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

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指令(无论方法正常/异常结束)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/468736.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 7.1 32位apk导致的系统库找不到问题

出现问题 因为我们安卓7.1系统的应用都是64位的APK,我们自己开发的应用是32位的APK,这样在启动的时候,就大概率的出现库找不到的问题。 错误的日志如下: Line 440: 03-12 10:48:39.620 634 634 W PackageManager: Instruct…

python基础知识下载_Python基础知识(一)

一、安装pythonwindow系统下先下载的 python 安装包,直接安装即可。为确认是否安装正确,可用系统记事本创建一个hello.py的程序其中包含如下内容:1 #!/usr/bin/env python32 print("Hello", "World!")代码说明&#xff1…

单词的理解 —— 词义的变化(翻译)

mimic:模仿,摹拟(而不是最小化)minder:n. 看守者;照顾者 保镖等近似含义;outstanding,outstanding work: 未完成的工作,backlog:n. [管理] 积压的…

JVM类加载机制_字节码执行引擎_Java内存模型

类加载机制: 类加载生命期:加载(Loading),验证(Verification),准备(Preparation),解析(Resolution),初始化(Initialization),使用(Using),卸载(Unloading)初始化:1.遇到new,getstatic,putstatic,invokestatic指令,类没有进行初始化,先触发初始化2.java反射机制3.初始化一个类,…

最新车载导航端口检测工具_高德地图这个功能 把微信都没做好的车载社交解决了?...

在汽车网联化和智能化带给人们的诸多想象里,车内社交似乎是最虚无缥缈的那个。在移动互联网领域,微信通过满足人们社交需求这个基本点,构建起庞大的用户群体,展示出巨大的市场前景。但在驾车场景下,车载社交该怎么玩&a…

王译潇20162314 第九周作业总结

学号 20162314 2016-2017-2 《Java程序设计》第九周学习总结 教材学习内容总结 数据库是为其他程序提供数据的应用软件 关系数据库通过唯一的标识符在不同表的记录间建立了关系 JDBC API用来建立到数据库的连接 CREATE TABLE SQL 语句用来创建新的数据库表 ALTER TABLE SQL 语句…

sketchup边线设置_春天花花天桥,SketchUp草图大师快速建模!

最近小吧在网上看到一座设计很特别的天桥,形状很像一朵花,名字也十分写实——春花天桥。喏,就是下面这个家伙!图片来自网络春花天桥是2011年深圳举办大运会前夕投资建设的形象提升工程之一,在建设初期就被定位为地标性…

自言自语

随笔, 自我审视, 需要反思 最近这段时间, 各种艰难困苦早已将最初的激情冲刷地只剩下骨头了, 每天拖着疲惫的身子, 总是做着没有意义的事; 迷失了自我, 总把时间浪费, 而在做浪费时间的事却没有思考做这件事是否是有意义的, 是否是有价值的, 是否是在浪费时间; 没有思考, 就像行…

忧愁无处发

顶着好多方面的压力回家了....过得不好。。。。转载于:https://www.cnblogs.com/ysw6/p/6789910.html

python求直角三角形第三边公式_直角三角形已知两边求第三边公式

展开全部解:分两种情况讨论1、需要求的第三边为斜边时,第e69da5e887aa3231313335323631343130323136353331333433643030三边长度√a^2b^2 (ab分别为两直角边的长度)2、需要求的第三边为直角边时,第三边长度√c^2-a^2 (其中c为斜边,a为已知直角边)扩展资料…

android 7.1 apk的systemuid和系统应用Setting相同导致开机找不到库的问题

1、前言Android apk加载机制这就是我最近在解决的一个问题,32位的apk可以用32位的库,那64位的apk可以用64位的库,如果我想64位的apk同时使用32和64位的库呢?android加载so文件的机制apk在安装的过程中,系统就会对apk进…

Struts2_1_基础案例_配置文件详解_动作类

Struts2简要概述 三层架构中的表现层框架相对于常规的MVC模式, 其核心为Filter控制器内部的Filter实例是在客户端每发送一次就实例化一次, 相比于Servlet具有线程安全性内部控制器默认拦截以.action或无后缀名的url Struts2案例步骤 配置web.xml, 由于Struts2核心为Fiter, 所…

BZOJ 3362 Navigation Nightmare 带权并查集

题目大意:给定一些点之间的位置关系,求两个点之间的曼哈顿距离 此题土豪题。只是POJ也有一道相同的题,能够刷一下 别被题目坑到了,这题不强制在线。把询问离线处理就可以 然后就是带权并查集的问题了。。。将权值设为方向向量&…

怎样的人适合当码农?

1高中的时候,我一个友仔,他说要创办一个科技协会,然后跟我说电脑里面的代码都是0和1组成的,我现在还记得那天我们在学校开会的时候讨论电脑如何运行,我一脸痴呆的听他给我讲解电子知识,而且他后面自己做了一…

Struts2_2_解决配置文件冗余_动作类对象数据封装_数据类型转换_表单数据信息提示

Struts2第二天学习 解决struts.xml文件的冗余 将所有的配置文件放在一份struts.xml将会导致, 文件繁杂且容易出错, 将有如下的解决方案: 分文件编写Struts2的配置文件:对于具有类似功能的action就可以放入不同对应的xml文件中, 最后使用struts标签中的<include file"…

高版本号chrome安装flashplayer debuger后无法使用的问题

起因应该是苹果公司指出flash player的安全问题&#xff0c;还有各种原因导致google将在未来取消NPAPI的支持&#xff0c;所以fp们就悲剧了在高版本号chrome&#xff08;42以上&#xff09;默认是关闭外部安装的插件使用的&#xff0c; 所以在地址栏通过chrome://flags/#enable…

android 7.1 apk的systemuid [2]

1 上周发的一篇文章《android 7.1 apk的systemuid和系统应用Setting相同导致开机找不到库的问题》&#xff0c;然后有个小伙伴找我讨论了&#xff0c;觉得自己的脑洞了打开了很多&#xff0c;所以针对这个问题再次做一次总结&#xff0c;如果大家有好的建议也可以在文末留言。…

python连连看小游戏_python实现连连看游戏

编程一直是在课余时间&#xff0c;放假时间自学&#xff0c;到现在为止也有半年了。这是我自己用python实现的连连看&#xff0c;也是第一个完成的游戏&#xff0c;虽然极其简陋。思路呢&#xff0c;一开始是想要从一个点出发开始寻路&#xff0c;遇到数字就换一条路&#xff0…

Struts2_3_国际化处理_自定义拦截器_文件上传及下载_OGNL

Struts2国际化处理 浏览器根据当前的语言环境自动查找对应的语言环境资源包, 使jsp显示合适的语言数据环境 Struts2实现国际化, 动作类必须继承ActionSupport 创建资源包 资源包由多个properties文件组成, properties文件的文件名必须满足命名规范: 文件名_语言代码_国家代码…

RBAC 基于角色的访问控制

RBAC&#xff08;Role-Based Access Control&#xff0c;基于角色的访问控制&#xff09;&#xff0c;就是用户通过角色与权限进行关联。简单地说&#xff0c;一个用户拥有若干角色&#xff0c;每一个角色拥有若干权限。这样&#xff0c;就构造成“用户-角色-权限”的授权模型。…