Java类文件结构及类加载机制

104 阅读3分钟

「这是我参与2022首次更文挑战的第22天,活动详情查看:2022首次更文挑战」。

计算器只认识0和1,那么我们写的java代码是怎么被操作系统识别并执行的呢?

其实这里就是虚拟机起了很多作用了,JVM定义了一套字节码规范,只要符合虚拟机规范的字节码就可以被虚拟机识别,加载,执行 ,class文件就是字节码的来源,JVM通过 ,可见CLASS文件是JVM平台的基石。

class文件结构是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑的排列在class文件之中,中间没有任何分隔符。

包含两种数据结构:

1、无符号数:基本的数据类型,以u1,u2,u4,u8代表1,2,4,8个字节的无符号数,用来描述数字,索引引用,数量值

2、表:由无符号数或者其他表作为数据项构成的复合数据类型,以_info结尾

u4 magic 魔术,  身份识别,是否可以被虚拟机接受

u2 minor_version  高版本可以兼任低版本 jdk1 以45为版本号

u2 major_version 

cp_info 常量池 存储字面量和符合引用  类和接口全限定名 字段的名称和描述符 方法的名称和描述符

javap a.class javap命令可以查询class文件字节码

类加载机制

class文件格式了解了,但是这些class文件是怎么被虚拟机识别加载到内存的,这里会经历一些过程。

类加载生命周期:加载,验证,准备,解析,初始化,使用,卸载

加载:通过类全限定名进行获取二进制字节流

验证:文件格式,元数据,字节码,符号引用等验证

准备:为类变量分配类型并设置类初始值

解析:将符号引用替换成直接引用,包括类或接口的解析,字段解析,类方法解析,接口方法解析

初始化:当遇到new ,getstatic,puttstatic,invokestatic指令时进行初始化,方法中会对变量赋值或者静态代码块的初始化

静态代码块只能访问在静态代码块定义之前的变量,定义在它之后的变量可以赋值,但是不能访问,并且总是会先执行父类的方法

虚拟机天然保证在多线程下会正确执行,只会有一个线程同时执行

类加载机制:双亲委派模型

启动类加载器:加载java_home/lib下的jar文件

扩展加载器:加载java_home/lib/ext的jar文件

应用类加载器:加载用户类路径classpath下的类文件

双亲委派模型以组合关系来复用父类加载器代码。

工作过程:一个类加载器收到加载类请求时,首先会把加载请求委派父类加载器去完成,只有当父类加载器反馈自己加载不了当前请求的类,它才会自己去加载。如下图:

 

双亲委派机制好处:保证一个类只会被一个类加载器加载,保证了系统的稳定可靠性。使得java类有了一种层级关系。

破坏双亲委派机制的例子:

spi提供的接口的实现类启动器类无法加载,所以有了线程上下文类加载器,例如jdbc,jndi