本文会用最通俗的话讲解Java类的加载机制,助你彻底玩转Java类的加载机制,奥利给!
一、java代码在JVM中经历的三个阶段:编译、加载、实例化编译,首先Java代码如Person.java文件,通过javac命令进项编译,形成.class文件如Person.class文件;加载,然后通过类加载器将.class文件加载入内存;本文就是讲解此阶段——Java类的加载机制实例化,当需要实例化时,通过new 关键字生成对象实例;
二、类加载阶段:类加载阶段包括:加载、验证、准备、解析、初始化几个阶段,相信很多人背过,背了忘忘了背,我之前也是,还曾创造出“加盐备姐,初始化”的顺口溜,帮助记忆。哈哈,其实如果完全理解这几个阶段是干什么的,不需要死记硬背的
此处的加载是类加载阶段的第一个阶段,只是类加载阶段的一部分,容易混淆,注意区分。
加载阶段会做以下事情:类加载器加载.class文件,转化为某种静态数据结构放入方法区,并在堆中生成一个方便用户使用的Java.lang.Class类型的Class对象(堆里的此Class类就是元数据),供用户使用:
需要注意的是,此处的.class文件不一定仅仅是本地的文件,还有可能来源于网络传输、或者动态生成的.class文件,如动态代理时生成的代理类
加载阶段虽然已经在方法区中存在类的静态数据结构,且堆中已经存在了Class对象,但不代表JVM已经认可了此对象,还需要进行连接,连接的第一步就是验证:
- 对文件格式进行验证,这一步实际上是在加载阶段进行的对方法区的类的元数据、字节码进行验证,通俗的说就是验证类的静态结构的语法与语义,保证其不会危害虚拟机除了文件格式、元数据与字节码,还会对符号引用进行验证,但是符号引用是解析阶段进行的,解析阶段可以在初始化之前或之后进行。
在元数据与字节码验证完之后,虚拟机姑且认为此Class是安全的,接下来进入准备阶段,准备阶段主要是为类的静态变量与常量赋初始值:
针对static修饰的静态变量会赋默认值(如0、0L、null、false等)常量直接赋设置的值(赋初值不是赋默认值,如果不是字面值静态常量,那么会和静态变量一样赋默认值) 六、步骤四:解析
准备阶段结束以后会进入解析阶段,解析阶段是将对象的符号引用变为直接引用:
如A类中引用的B类,A在编译的过程中不知道B是否被编译,且B肯定为进入加载阶段,所以A肯定不知道B类的实际地址,那么A怎么找到B呢?此时在A的.class文件中会用一段符号(如B的全限定类名)表示B类,此符号就称为符号引用;如果到解析阶段B类还为加载此时会触发B类的加载,将B加载的虚拟机中,并将A中的符号引用替换成B的实际地址,即直接引用,这样A类就能直接调用到B了。称为静态解析。
静态解析只是简单的情况,除了静态解析还有动态解析,如果使用了多态,B是接口或者是抽象类,而C、D类是B的两个具体实现类,那么A就不知道B的具体地址是什么,不知道那就等一等,等到虚拟机具体使用A类时,这个时候就知道具体使用B的哪个实现类,这个时候就可以用直接引用替换符号引用了,这就是为什么有时候解析阶段会发生在初始化之后的原因,因为是动态解析,实现了后期绑定。
解析步骤完成这证明整个连接阶段结束,这个时候,jvm就可以使用此类了。
初始化是判断类是否有主动初始化的动作,包括类的静态变量的赋值,静态代码块的执行。
最后实例化:此时通过new 关键字即可进行实例化



