您的位置:首页 > 编程语言 > Java开发

关于java从编译成class文件到加载再到初始化过程解析

2015-10-18 18:56 781 查看
一、class文件组成

magic魔数(标识是否为class文件)
min_version次版本号
major_version主版本号
constant_pool_count常量数量
contstant_pool_info常量信息
access_flag类的访问标识符
this_class当前类的符号引用
super_class父类的符号引用
interface_count实现接口数量
interface_info接口信息
field_count字段数量
field_info字段信息
method_count方法数量
method_info方法信息(方法访问标识符、参数列表、返回类型。包括code属性)
attribute_count属性数量
attribute_info属性信息(code(方法体)、exception)
二、class文件加载过程

过程:加载----->验证------>准备------>解析------>初始化

加载 发生的变化:

(1)、根据类的全名限定符,获取class二进制流(保存到硬盘的class文件,不是class二进制流获取的唯一方式。也有可能从网络中获取等)

(2)、将类的静态存储结构转化为方法区的运行时动态存储结构

(3)、在内存的堆中生成对应的class对象,作为方法区的入口

验证要做的事情:

(1)、class文件格式验证(class文件来源不唯一(自己也可以手写),有可能格式正确损坏虚拟机)

(2)、元数据验证(是否符合类的定义规范,例如是否继承java.lang.Object)

(3)、字节码验证(类中方法的控制流是否合法)

(4)、符号引用验证(转换为直接引用动作是否合法)

准备发生的事情:为类变量在方法区分配内存,并初始化类变量(“零值”初始化)

解析要干的事情:将常量池的符号引用替换为直接引用

初始化:在准备阶段已经对类变量进行初始化了,这里的初始化是执行类构造器<clinit>。<clinit>()方法是编译器自动收集类中所有类变量的赋值动作和静态代码块而产生的方法(无论类变量和静态代码块的位置是什么样,都是先执行类变量的赋值动作,再执行静态代码块)

初始化触发的条件,有且只有四个(主动引用)

(1)、new(实例化对象)、getstatic(获取类变量的值,被final修饰的除外,他的值在编译器时放到了常量池)、putstatic(给类变量赋值)、invokestatic(调用静态方法)

(2)、使用java.lang.reflect包的方法对类进行反射调用方法

(3)、初始化类的时候,如果他的父类还没有初始化,要先初始化父类

(4)、虚拟机启动时,含有main方法的类,会被先初始化

被动引用(除了上面引用类的四个条件会触发类的初始化,其他对类的引用都不会触发类的初始化):

(1)、在第三方类中,使用子类引用父类的类变量,不会初始化子类

(2)、在第三方类中,通过数组定义来应用类,不会初始化类

(3)、在第三方类中,引用类的常类变量(同时被final和static修饰的变量),不会触发类的初始化(因为在第三方类的编译之后,常量就被放在第三方类的常量池中了)

三、虚拟机的内存分配情况

(1)、虚拟机栈:每个class类对应一个虚拟机栈帧(组成:局部变量表、操作数栈、返回地址、动态链接),类私有

(2)、堆:存放对象

(3)、方法区:存放类信息、常量、类变量、即时编译器编译后的代码

(4)、常量池:是方法区的一部分,主要有字面量(常量和字符串)和符号引用(类和接口的符号引用、字段的名称和描述的符号引用、方法的名称和描述的符号引用)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  class java JVM