JVM的类加载机制

类加载器初始化的简单流程图

 

类加载的过程简单流程图

 

类加载的过程:

  1. 加载:在硬盘上查找并通过IO读入字节码文件,使用到类时才会加载,例如调用类的main函数、new对象等。在加载阶段会在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
  2. 验证:校验字节码文件的正确性。
  3. 准备:给类的静态变量【非常量】分配内存,并赋予默认值【整型默认0,布尔默认false,引用类型默认null】。
  4. 解析:把符号引用替换为直接引用,这个阶段会把一些静态方法【静态方法就是符号引用,比如main()函数】替换为指向数据所在内存的指针或句柄等【即直接引用】,这就是所谓的静态链接过程【在类加载期间完成】。动态链接是在程序运行期间完成的把符号引用替换为直接引用。
  5. 初始化:对类的静态变量初始化为指定的值,执行静态代码块。

 

类被加载到方法区后,主要包含运行时常量池、类型信息、字段信息、方法信息、类加载器的引用、对应class实例的引用等信息。

类加载过程主要是通过类加载器来实现的,Java中有以下几种类加载器:

  1. 引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar等。
  2. 扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包。
  3. 应用程序类加载器:负责加载ClassPath路径下的类包,主要就是加载你写的源代码。
  4. 自定义类加载器:负责加载用户自定义路径下的类包。

双亲委派机制

 双亲委派机制即按照上图从下往上去加载类,如果应用程序类加载器找到了类就直接返回,如果找不到就向上委托给扩展类加载器继续加载,同样找到就返回,如果还找不到就继续向上委托引导类加载器继续加载,还找不到就会向下委托给扩展类加载器去加载,还加载不到又继续向下委托到应用程序类加载器加载,还找不到就会报ClassNotFound异常了。

是不是感觉有点绕?跑了一圈又回来了!

你可能会问既然要这样绕一圈,为什么不直接从引导类加载器开始加载类呢?我猜测可能是因为需要加载的类大部分都是你写的源代码,即只有应用程序类加载器才能加载到的类,既然大部分都是它才能加载到的,干脆直接从它开始加载好了。这只是我的猜想哈!更具体的原因,也许只有JVM的研发人员才知晓了吧!

 

 

 为什么要设计双亲委派机制?

  1.  沙箱安全机制:自己写的与核心类库中类名相同的类不会被加载,比如自己写的java.lang.String.class,这样可以防止核心API库被随意篡改。 
  2. 避免类的重复加载:当父类加载器已经加载到该类时,子类加载器就没必要再次加载,这样可以保证被加载类的唯一性。

 全盘负责委托机制

“全盘负责”是指当一个ClassLoader装载一个类时,除非显示地使用另外一个ClassLoader,该类所依赖以及引用的类也由这个ClassLoader载入。

打破双亲委派机制

打破双亲委派机制就是不委托父加载器去加载类了,而是自己一次性去加载类,可以通过重写loadClass方法实现。

 感谢图灵学院的诸葛老师!!

posted @ 2022-08-30 15:32  敲代码的小浪漫  阅读(63)  评论(0编辑  收藏  举报