Granda's Blog

JAVA:类加载机制

JVM和类

  • 系统可能在第一次使用某个类的时候加载该类,也可能采用预加载机制来加载某个类
  • JVM进程终止:
    1. 程序正常结束
    2. 使用System.exit()或者Runtime.getRuntime().exit()结束程序
    3. 程序运行过程中遇到未捕获的异常或者出错结束
    4. 程序所在平台强制结束了JVM进程

类的加载

  • 类被加载到内存中时,会经过加载,连接,初始化三个步骤
  • 类的加载是指将编译好的class文件读入内存中,并为之创建一个java.lang.Class对象
  • 类的加载由类加载器完成,可以通过继承ClassLoader基类来创建自己的类加载器
  • 使用不同的类加载器,可以从不同来源加载类的二进制数据(本地文件系统、JAR包、网络)

类的连接

  • 连接阶段负责把类的二进制文件合并到JRE中
  • 连接有三个阶段:
    1. 验证:检验被加载的类是否有正确的内部结构
    2. 准备:负责为类的类变量分配内存,并设置默认初始值
    3. 解析:将类的二进制数据中的符号引用替换成直接引用(编译到二进制文件的是符号引用,类加载之后才是直接引用)

类的初始化

  • 主要是对类变量进行初始化
  • 要先初始化该类的父类,所以JVM最先初始化的是java.lang.Objext类
  • 类初始化的时机:
    1. 创建类的实例
    2. 调用某个类方法
    3. 访问某个类变量
    4. 使用反射来创建Class对象
    5. 使用java运行某个主类
  • final修饰的类变量,如果值在编译的时候已经确定,那么该变量是“宏变量”,在编译的时候会被替换,调用“宏变量”时,不会导致被加载
  • 使用ClassLoader类的loadClass()方法,只会加载该类,不会执行类的初始化
  • 使用ClassLoader类的forName()方法才会强制初始化该类

类加载器

  • 在JVM中,一个类用类的全类名+类加载标识
  • JVM启动时,会形成由三个类加载器组成初始类加载器层次结构:
    1. Bootstrap ClassLoader:根类加载器,由JVM自身实现,负责加载Java核心类
    2. Extension ClassLoader:扩展类加载器,负责加载JRE扩展目录(%JAVA_HOME%/jre/lib/ext)中JAR包的类
    3. System ClassLoader:系统类加载器,负责JVM启动时来自java命令的-classpath选项
  • URLClassLoader类:URLClassLoader(URL[] urls),使用默认的父类加载器创建一个ClassLoader对象,指定类的URL,可以是本地文件系统,也可以来自网络。然后调用该对象的loadClass()方法来加载指定的类
    1
    2
    3
    URL[] urls = {new URL("file:mysql-connector-java-5.1.30-bin.jar")};
    URLClassLoader myClassLoader = new URLClassLoader(urls);
    Driver driver = (Driver)myClassLoader.loadClass("com.mysql.jdbc.Driver").newInstance();