JVM类加载分为5个过程:加载,验证,准备,解析,初始化,使用,卸载,如图: java
没错,以上就是抽象的类加载过程,写类加载过程的都是大同小异,图我也是copy来的,而后联想到近期刚刚入职新公司,下面我入职新公司来解释类加载(绝对通俗易懂):程序员
场景:企业A发offer,约定6月17号入职,为我分配了部门,入档,部门领导人在周例会汇报中报备部门成员XXX(待入职)面试
(1) 找:经过一个类的全限定名来获取此类的class字节码二进制流。(给一个名称找到class字节码文件=经过面试邮箱发offer)安全
(2) 转:将这个字节码二进制流中的静态存储结构转化为方法区中的运行时数据结构。(转化为线程共享内存方法区的运行时数据结构=???这个很差解释)数据结构
(3) 存:在内存中生成一个表明该类的java.lang.Class对象,做为方法区中这个类的各类数据的访问入口。(在方法区中为类实例化一个源对象,目的是做为方法区这个类的各类数据的访问入口=企业A为我分配部门,入档,领导内部沟通时能够用XXX部门的XXX人员)函数
注: 1.在JVM中类的惟一性是由类的全名和类加载器肯定的,相同的class文件被不一样的类加载器加载生成的两个类是不一样的。 2.加载阶段和链接阶段的部份内容是交叉进行的,加载阶段还没有结束,链接阶段可能就已经开始了。 3.源对象只会存放静态资源,如static变量线程
场景:6.17号,本人入职递交材料,如体检/上家企业的离职报告,hr领我到对应工位,并提供企业文化和流程等相关文档文件,并在座位上配备人员信息(其实就是一张卡片,职位姓名之类的信息),目的让其余人能够看见cdn
验证:确保加载的类信息符合JVM规范,没有安全方面的问题 (对实例化对象进行各类校验,好比语法/符号 = hr检查材料是否交齐,并有没有做假)对象
准备:正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配 (在源对象的基础上为static变量开辟空间并设置初始值=hr领我到工位,做为个人办公区)blog
解析:虚拟机常量池的符号引用替换为字节引用过程 (将抽象的指令转换为具体的地址指令=配备信息卡片,当其余找我时,只须要看到卡片上的名字就能够了)
注: 1.public static Integer value=1;在准备阶段的值实际上是为0的。须要注意的是常量是在准备阶段赋值的:public static final Integer value =1 ;在准备阶段value就被赋值为了1;
2.解析的过程:好比在类A中调用了B的方法;你们想想,咱们编译完成.class文件后其实这种对应关系仍是存在的,只是以字节码指令的形式存在,好比 "invokespecial #2"你们能够猜到#2其实就是咱们的类B了,那么在执行这一行代码的时候,JVM咋知道#2对应的指令在哪,这就是一个静态的家伙,假如类B已经加载到方法区了,地址为(#f00123),因此这个时候就要把这个#2转成这个地址(#f00123),这样JVM在执行到这里时就知道B类在哪了,就能够去调用了。甚至Java 虚拟机为每一个类都准备了一张方法表来存放类中全部的方法。当须要调用一个类的方法的时候,只要知道这个方法在方法表中的偏移量就能够直接调用该方法了
场景:入职以后,在以前入档的基础上初始化我的信息和各类帐号,如邮箱,域帐号域密码等
注:1.前面的类加载过程当中,除了加载(Loading)阶段用户应用程序能够经过自定义类加载器参与以外,其他动做彻底由虚拟机主导和控制。
2.一个类什么时候被初始化能够分为如下几类:A:建立类的实例(new)。B:访问某个类或接口的静态变量,或者对该静态变量赋值。C:调用类的静态方法。D:经过反射方式执行以上三种行为。E:初始化子类的时候,会触发父类的初始化。F:Java虚拟机启动时被标明为启动类的类。(有main方法的类)
3.初始化完成之后,类被存放在方法区,注意哦,此时并无存放在堆内存中。只有当对象实例化进入堆内存中之后才会对非静态变量进行初始化赋值。
场景:有帐号密码了,能够工做了,直到下次离职,开始工做啦。。。。。。。
1.使用:直接new或者经过反射.newInstance,堆内存建立实例化对象.(等同于开始工做了,领导安排任务)
2.卸载:卸载是自动进行的,也就是GC,gc在方法区也会进行回收.不过条件很苛刻,感兴趣能够本身看一看,通常都不会卸载类.(下次离职。。。。😂)