类的加载机制

1.双亲委派模型

每次收到类加载请求时,先将请求委派给父类加载器完成(所有加载请求最终会委派到顶层的Bootstrap ClassLoader加载器中),如果父类加载器无法完成这个加载(该加载器的搜索范围中没有找到对应的类),子类尝试自己加载。

2.类加载器的种类

  • 启动类加载器,Bootstrap ClassLoader,加载JAVA_HOME\lib,或者被-Xbootclasspath参数限定的类
  • 扩展类加载器,Extension ClassLoader,加载\lib\ext,或者被java.ext.dirs系统变量指定的类
  • 应用程序类加载器,Application ClassLoader,加载ClassPath中的类库
  • 自定义类加载器,通过继承ClassLoader实现,一般是加载我们的自定义类

3.自定义加载器

  • 继承java.lang.ClassLoader类,然后覆盖它的findClass(String name)方法即可,即指明如何获取类的字节码流
  • 如果要符合双亲委派规范,则重写findClass方法(用户自定义类加载逻辑);要破坏的话,重写loadClass方法(双亲委派的具体逻辑实现)

4.类的加载过程

  • 加载:获取二进制字节流,将其转化成运行时数据结构存储在方法区,生成calss对象作为获取数据的方法区入口;
  • 验证:对元数据,文件格式,字节码,符号引用的验证,可通过--Xverifynone参数关闭大多数的验证;
  • 准备:为静态变量分配内容,并给予默认值;并不是代码中实际的值;
  • 解析:将常量池中的所用符号引用转为直接引用(类,变量等的内存指针);
  • 初始化:收集器顺序收集源文件的语句,将所有的类变量初始化语句和静态代码块存放到一个特殊的方法-<clinit>中,该方法只能在类加载的过程中由JVM调用;
  • 使用:类的使用;
  • 卸载:gc回收;

4.1.注意点

  • 静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。
  • 常量调用不会触发类加载
  • 由JVM负责保证一个类的<clinit>方法执行之前,它的超类<clinit>方法已经被执行
  • JVM能确保一个类的初始化在多线程中只有一个线程能初始化成功
  • 如果一个类没有声明任何的类变量,也没有静态代码块,那么可以没有类<clinit>方法

5.触发类的加载

  • 访问静态成员、方法时,会加载类;加载的类仅限于成员所属类及其父类,且仅加载静态域和静态成员
  • 第一次new对象会加载类
  • 访问类的public静态常量,常量值能确定,不会加载类;不能确定会加载类
  • 初始化一个类的派生类
  • JVM启动包含main方法的启动类
  • 调用JavaAPI中的反射方法

6.接口与类的加载区别

接口中不能使用静态语句块,但仍然有变量初始化的赋值操作,因此接口与类一样都会生成<clinit>()方法。但接口与类不同的是,执行接口的<clinit>()方法不需要先执行父接口的<clinit>()方法。只有当父接口中定义的变量使用时,父接口才会初始化。另外,接口的实现类在初始化时也一样不会执行接口的<clinit>()方法。

7.热部署

在不重启 Java 虚拟机的前提下,能自动侦测到 class 文件的变化,更新运行时 class 的行为;步骤如下:

  • 销毁自定义classloader(被该加载器加载的class也会自动卸载);
  • 更新class;
  • 使用新的ClassLoader去加载class ;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值