JVM的类加载机制和加载器的理解

JVM的类加载机制Class的载入7大阶段

  1. 加载: 从文件或者其他地方将一个类的字节信息加载到内存中,
  2. 验证:验证字节信息是否符合虚拟机的规范,防止格式不对的字节码信息载入到虚拟机中
  3. 准备:开始在内存中准备一些静态变量区域,并且给这些变量赋初始值。 比如Int的初始值为0
  4. 解析: 替换符号引用为直接引用。比如: 类中是通过类名来关联其他类的, 但是类名无法表示其他类的在内存中的位置, 这一步就是把类名替换成真正的类在内存中的应用。
  5. 初始化: 在前面已经为类在内存中开辟空间了, 这一步就是把类中定义的静态值赋值进去。 这一步结束后,程序就可以正常使用类了。

类构造

是虚拟机根据类的内部定义自动生成的, 在初始化阶段会执行这个构造器。 在构造器中会给一些静态变量赋初值。 虚拟机会保证父构造器先于子构造器执行, 如果类中没有静态变量或者代码块。 构造器可以不用执行。
类的初始化时懒初始化的, 只有在必须初始化的时候才会初始化:

  1. 通过子类引用父类的静态字段,只会触发父类的初始化,而不会触发子类的初始化。
  2. 定义对象数组,不会触发该类的初始化。
  3. 常量在编译期间会存入调用类的常量池中,本质上并没有直接引用定义常量的类,不会触发定义常量所在的类。
  4. 通过类名获取 Class 对象,不会触发类的初始化。
  5. 通过 Class.forName 加载指定类时,如果指定参数 initialize 为 false 时,也不会触发类初始化,其实这个参数是告诉虚拟机,是否要对类进行初始化。
  6. 通过 ClassLoader 默认的 loadClass 方法,也不会触发初始化动作。

类加载器

在这里插入图片描述
jdk自带三个类加载器

  1. 启动类加载器(Bootstrap ClassLoader):负责加载JAVA_HOME\lib目录中的,或通过-Xbootclasspath 参数指定路径中的,且被虚拟机认可(按文件名识别,如 rt.jar)的类。
  2. 扩展类加载器(Extension ClassLoader): 负责加载JAVA_HOME\lib\ext目录中的,或通过 java.ext.dirs 系统变量指定路径中的类库。
  3. 应用程序类加载器(Application ClassLoader):负责加载用户路径(classpath)上的类库。

应用中我们自定义的类是通过Application ClassLoader 来加载的。 java的类的加载有双亲委派的机制

双亲委派的机制

当一个加载器开始加载一个类之前,会调用上级的加载器委托上级加载器来加载,上级加载器也是同样的操作,一直委托到最顶级的启动类加载器,此时启动类加载器就会判断要加载的类是否是自己可以加载的类,如果不是会将加载操作在返回下级加载器, 下级加载器也会判断下自己可以加载不, 如果可以就会加载类, 加载成功后在通知下级下载器不要忙了,类已经加载了。

双亲模型的优点:

  1. 无论什么加载器,都无法加载虚拟机的类。 这样对虚拟机是一种保护,防止应用程序破坏虚拟机的正常运行。
  2. 防止一个类被不同的加载器重复加载

双亲模式的缺点:
Jdk中的类无法加载用户的类, 比如JDBC的DriverManager类是接口在rt.jar中, 是属于启动类加载器加载的, 但是他的java.sql.DriverManager#getConnection(String, Properties,Class<?>)方法需要加载的了是各个数据库厂商实现的jdbc的驱动类。 数据库厂商实现的类肯定是需要应用程序类加载器或子加载器来加载的。

java中如果A类内部加载了B类, 那么B类会使用和A类的Classleader

DriverManager是属于jdk内部的类, 但是DriverManager的getConnection方法却会加载厂商实现的jdbc驱动类, 驱动类是用户自己实现的,应该由Application Classloader 来加载的,但是DriverManager是如何调用实现加载jdbc的类的呢?
解决: 线程上下文类加载器。
一个程序的启动类肯定是用户类, 他的加载肯定是Application Classloader, jdk会在启动的时候把这个加载器放入主线程上下文中。 主线程在创建其他线程的时候,会把这个加载器传递下去。 而DriverManager中是取得了线程上下文加载器来加载驱动类的。 这样就实现了jdk中的类加载了用户的类。

Tomcat 的类加载器

tomcat基于自己的特性, 自定义了自己的类加载器。
在这里插入图片描述

问: 一个tomcat可以允许多个webApp应用,他们都是在一个jvm上运行的, 那么这个多个webApp是否可以互相调用呢?

答: 不行, 每个webApp都有自己的唯一的类加载器并且只加载本应用的目录中的类, 多个应用的类加载器的关系是平级的,就是说A应用的加载器不会去加载B应用。 同样B也是如此。
并且tomcat的启动类在tomcat的启动脚本中, 你的因为也无法通过线上上下文获取其他应用的类加载器

问: 为什么Catania.lib目录中的类优先级最高, 并且里面的类会覆盖所有应用的同名类?

因为common加载器是所有webApp加载器的上级加载器, 如果webapp要加载其中的同名类,就会委派到common加载器来加载,它会加载Catania.lib目录下的同名类,自然就屏蔽了各个应用的类了, 所以优先级很高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值