zoukankan      html  css  js  c++  java
  • jvm--1.class文件结构

    1.字节码
    (1)bytecode是构成平台无关性的基石

    (2)当jvm发展到1.7-1.8的时候,jvm设计者通过,JSR-292,基本可以让其他语言运行在jvm上面。
    如,Clojure , Groovy , JRuby , Jython , Scala

    (3)jvm不和包括java在内的任何语言绑定, 它只和Class文件这种二进制文件格式关联。
    Class文件,包含了jvm 指令集 和 符号表 ,以及其他若干信息。

    (4)虚拟机不关心class文件的来源是何种语言。

    java程序(*.java) --> java编译器

    JRuby程序(*.rn) --> jruby编译器
    ---->字节码(*.class) -->java虚拟机
    Groovy程序(*.groovy) --> groovy编译器

    其他语言 --> 其他编译器

    2.Class文件结构
    概念:
    (1)class文件,并非一定是一个磁盘文件,类或者接口也可以通过类加载器直接生成。
    (2)class文件,是一组以8位字节为基础单位的二进制流。没有任何分割符号。
    (3)class文件格式采用一种类似于C语言的结构体的伪结构来存储数据。
    这种为机构只有两种数据类型:无符号数 和 表。

    a.无符号数,属于最基本的数据类型,以u1 , u2 , u4 , u8 分别代表 1个字节 , 2个字节 , 4个字节 , 8个字节
    可以用来描述,数字、索引引用、数量值、字符串

    b.表,由无符号数,或其他表,作为数据项构成的,复合型数据类型。
    所有的表习惯性的以 ”_info“ 结尾。
    用于描述有层次关系的复合结构的数据。
    整个class文件本质上就是一张表。
    结构:
    (4)魔数
    a.每个Class文件的头四个字节称为魔数(Magic Number) ,它的唯一作用是用来确定这个文件是否能被jvm所接受的Class文件。
    值为:0xCAFEBABE

    (5)版本号
    a.紧跟着魔数的四个字节,存储的是class文件的版本号:
    第5和第6个字节是次版本号,第7和第8个字节是主版本号。
    b.java版本号是从45开始的,JDK1.1之后的每个大版本发布,主版本号向上加1
    JDK1.1支持: 45.0 ~45.65536
    JDK1.2支持: 46.0 ~46.65536
    JDK1.3支持: 47.0 ~47.65536
    JDK1.4支持: 48.0 ~48.65536
    JDK1.5支持: 49.0 ~49.65536
    JDK1.6支持: 50.0 ~50.65536
    JDK1.7支持: 51.0 ~51.65536
    JDK1.8支持: 52.0 ~52.65536
    c.高版本的JDK能向下兼容以前版本的Class文件,但低版本不能运行高版本的Class文件。即使文件格式没有发生变化,虚拟机也必须
    拒绝执行,超过其版本号的Class文件

    d.jdk的版本号和jvm的版本号对应。

    (6) 常量池(每个Class文件都有)
    a.紧接着主次版本号的是常量池入口,常量池可以理解为Class文件中的资源仓库,第一个出现的表类型数据结构。
    由于常量池常量的数量是不固定的,所以,在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值(constant_pool_count)。
    这个计数值是从1而不是从0开始的。因为某些指向常量池的索引值在特定情况下需要表达,不引用任何一个常量池。

    b.存放:
    字符串,声明为final的常量值。
    类和接口的全限定名(com.lvyf.Test)
    字段的名称和描述
    方法的名称和描述,不包括方法返回值

    c.*.java文件在进行,javac编译的时候,并不像C有连接这一步,而是在jvm加载Class文件的时候进行动态连接。也就是说,Class文件不会
    保存各个方法,字段,的内存布局。因此,这些字段、方法不经过运行期转换的话无法得到内存地址,也就无法被虚拟机使用。
    (就是 javac在编译的时候,把方法字段需要的内存信息,放到常量池,而不给方法和字段分配内存地址)当JVM运行Class文件时,
    需要从常量池,获取对应的符号引用,再在类创建或者运行时解析、翻译到具体的内存地址。

    d.java常量池有个计数器(因为常量池是不固定的,需要有计数器保存常量池长度),计数器数据类型是u2(2个字节2的16次方,65536),所以
    java中如果定义超过64KB的英文变量名或者方法名,将会无法编译。

    (7)访问标志
    常量池结束之后,是访问标志(access_flag),识别类或者接口的访问信息
    a.Class是类还是接口
    b.是否为public类型
    c.是类的话,是否为abstract类型
    d.是否为final类型

    (8)字段表集合field_info,用于描述接口或类中的变量
    包括类变量,和实例级变量,不包括局部变量
    a.字段的作用域(public , private , protected)
    b.是实例变量还是类变量(static修饰)
    c.可变性(final修饰)
    d.并发可见性(volatile修饰,是否强制从主内存读写)
    e.是否可被序列化(transient修饰)
    f.字段类型(8中基本类型,对象,数组)
    h.字段名称。
    各个修饰符都是boolean值

    (9)方法表集合,
    a. 访问标志
    名称索引
    等。。。
    b.code,方法里面的代码,经过编译成字节码后,存放在方法表集合中一个名为code的属性里面,接口没有code属性
    code最大值也是65536
    c.在java语言中,要重载一个方法,除了要与原方法有相同的名字,还要求必须与原方法有一个不同的特征签名,
    特征签名,就是方法信息在常量池中的描述,这个描述,不包括方法的返回值,所以,不能根据返回值的不同,来重载方法。
    要根据参数类型和参数个数,来重载方法。

    (10)max_stack
    代表了操作数栈深度的最大值。在方法执行的任意时刻,操作数栈都不会超过这个深度。

    (11)max_locals
    代表了局部变量所需的存储空间。单位是slot ,slot是虚拟机为局部变量分配内存的最小单位。
    对于byte,char,float,int,short,boolean等长度不超过32位的数据类型,需要1个slot,
    double,long需要两个slot

  • 相关阅读:
    LintCode: Climbing Stairs
    LintCode: Binary Tree Postorder Traversal
    LintCode: Binary Tree Preorder Traversal
    LintCode: Binary Tree Inorder Traversal
    Lintcode: Add Two Numbers
    Lintcode: Add Binary
    LintCode: A + B Problem
    LintCode: Remove Linked List Elements
    LintCode:Fibonacci
    Lintcode开刷
  • 原文地址:https://www.cnblogs.com/fubaizhaizhuren/p/5938472.html
Copyright © 2011-2022 走看看