1.JVM在什么情况下会加载一个类?
2.从实用角度出发,来看看验证、准备和初始化的过程
3.核心阶段:初始化
4.类加载器和双亲委派机制
我们首先从.java代码文件,编译成.class字节码文件 然后类加载器把.class字节码文件中的类给加载到JVM中
接着JVM来执行我们写好的那些类中的代码
一个类 从加载到使用,一般会经历下面的这个过程
加载-》验证-》准备-》解析-》初始化-》使用-》卸载
所以首先要搞明白一个问题,就是JVM在执行我们写好的代码的过程中,一般在什么情况下加载一个类呢?
也就是说,啥时候会从.class字节码文件中加载这个类到JVM内存里来?
其实答案非常简单,就是在你的代码中用到这个类的时候
当你使用这个类的实例时,就会触发JVM通过类加载器,从字节码文件中加载对应的类到内存里来使用,
这样代码才能跑起来
从使用角度出发,来看看验证、准备、和初始化的过程
【验证阶段】 这一步就是根据java虚拟机规范,来校验你加载进来的.class文件中的内容,是否符合指定的规范
假如说,你的.class文件被人篡改了,里面的字节码压根不符合规范,那么JVM是没法执行这个字节码的
所以把 .class 加载到内存里之后,必须先验证一下,校验他必须完全符合JVM规范,后续才能交给JVM来运行
【准备阶段】这个准备工作,其实就是给类分配一定的内存空间,来一个默认的初始值
【解析阶段】这个阶段干的事儿,实际上是把符号引用替换为直接引用的过程,其实这个部分的内容很复杂,
涉及到JVM的底层,所以这里大家就暂时知道有这么一个阶段就可以了
其实三个阶段里,最核心的大家务必关注的,就是准备阶段,因为这个阶段是给加载进来的类分配好了内存空间,
类变量也分配好了内存空间,并且给默认的初始值。
核心阶段:初始化
之前说过,在准备阶段时,就会把我们的类给分配好内存空间
另外他的类变量也会给默认的初始值0和null,那么接下来,在初始化阶段,就会正式执行我们的类初始化的代码了
在准备阶段,仅仅是给类变量开辟一个内存空间,然后给个初始值0罢了 那么赋值的操作是在初始化的时候执行的
什么时候会初始化一个类?
此外还有一个非常重要的规则,就是如果初始化一个类的时候,发现他的父类还没有初始化,
那么必须先加载这个父类,并且初始化他的父类
类加载器和双亲委派机制
【启动类加载器】
Bootstrap ClassLoader 他主要是负责加载我们在机器上安装的java目录下的核心类
一旦JVM启动,那么首先就会依托启动类加载器,去加载你的Java安装目录下的lib目录中的核心类库
【扩展类加载器】
就是你的java安装目录下,有一个lib\ext目录,这里面有一些类,就是需要使用这个类加载器来加载的,
支撑你的系统的运行。那么你的JVM一旦启动,是不是也得从Java安装目录下,加载这个lib\ext目录中的类
【应用程序类加载器】
这类加载器就负责去加载ClassPath环境变量所指定的路径中的类
其实你大致就理解为去加载你写好的java代码吧,这个类加载器就负责加载你写好的那些类到内存里
【自定义类加载器】
除了上面那集中之外,还可以自定义类加载器,去根据你自己的需求加载你的类
【双亲委派机制】
JVM的类加载器是有亲子层级结构的,就是说启动类加载器是最上层的,扩展类加载器在第二层,
第三层是应用程序类加载器,最后一层是自定义类加载器
什么是双亲委派机制?
就是假设你的应用程序类加载器需要加载一个类,他首先会委派给自己的父类加载器去加载,
最终传导到顶层的类加载器去加载,但是如果父类加载器在自己负责加载的范围内,
没有找到这个类,那么就会下推加载 权利给自己的子类加载器。
【比如你的JVM 要现在需要加载一个类,此时应用程序类加载器就会问自己的爸爸,也就是扩展类加载器,
你能加载到这个类吗?然后扩展类加载器直接问自己的爸爸,启动类加载器,你能加载到这个类吗?
启动类加载器心想,我在java安装目录下,没有找到这个类啊,自己找去!然后就下推加载权利给
扩展类加载器这个儿子,结果扩展类加载器找了半天,也没找到自己复杂的目录中有这个类。
这时他很生气,说:明明就是你应用程序加载器自己负责的,你自己找去。然后应用程序类加载器
在自己负责的范围内,比如就是你写好的那个系统打包成的jar包吧,一下子发现,就在这里,
然后就自己把这个类加载到内存里去了】这就是所谓的双亲委派模型:
【先找父亲去加载,不行的话再由儿子来加载】
这样的话,可以避免多层级的加载器结构重复加载某些类。
原文:https://www.cnblogs.com/imtm/p/14784676.html