ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] # 类装载过程 ![](https://box.kancloud.cn/159f59aea9a536c5802e5f2d79487850_853x351.png) 装载:通过累的全限定名获取二进制字节流,将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lang.class对象; 链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;   校验:检查导入类或接口的二进制数据的正确性;(文件格式验证,元数据验证,字节码验证,符号引用验证)   准备:给类的静态变量分配并初始化存储空间;   解析:将常量池中的符号引用转成直接引用; 初始化:激活类的静态变量的初始化Java代码和静态Java代码块,并初始化程序员设置的变量值。 # 简介 Java在需要使用类的时候,才会将类加载,Java的类加载是由类加载器来完成的。当在命令行模式下执行java XXX.class指令后,java运行程序会尝试找到JRE安装的所在目录,然后寻找jvm.dll(默认是在JRE目录下bin\client目录中),接着启动JVM并进行初始化动作,产生Bootstrap Loader,Bootstrap Loader会加载Extended Loader,并设定Extende Loader的parent为Bootstrap Loader。接着Bootstrap Loader会加载System Loader,并将System Loader的parent设定为Extended Loader。 Bootstrap Loader通常由C编写而成,Extended Loader是由Java编写而成,实际是对应于sun.misc.Launcher$ExtClassLoader(Launcher中的内部类).System Loader是由java编写而成,实际对你关于 sun.misc.Launcher$AppClassLoader(Launcher中的内部类)。 Bootstrap Loader会搜索系统参数sun.boot.class.path中指定位置的类,默认是JRE所在目录的classes下的.class文件,或lib目录下.jar文件中(如tr.jar)的类并加载。可用System.getProperty(“sun.boot.class.path”)来显示sun.boot.class.path中指定的路径。 Extended Loader是由Java编写而成,会搜索系统参数java.ext.dirs中指定位置的类,默认是JRE目录下的lib\ext\classes目录下的.class文件,或lib\ext目录下的.jar文件中的类并加载。 System Loader是由java编写而成,会搜索系统参数java.class.path中指定位置的类,也就是Classpath所指定的路径,默认是当前工作路径下的.class文件。 在加载类时,每个类加载器会先将加载类的任务交给其parent,如果parent找不到,再由自己负责加载。所以在加载类顺序为:Bootstrap Loader——》Extended Loader——》System Loader的顺序来寻找类,若都找不到,会抛出NoClassDefFoundError. 类加载器在Java中是以java.lang.ClassLoader类型存在,每一个类被加载后,都会有一个Class的实例来代表,而每个Class的实例都会记得自己是由哪个ClassLoader加载的。可以由Class的getClassLoader()取得加载该类的ClassLoader,而从ClassLoader的getParent()方法可以取得自己的parent # 分析 Class.forName()和ClassLoader.loadClass ~~~ Class.forName(className)方法,内部实际调用的方法是 Class.forName(className,true,classloader); 第2个boolean参数表示类是否需要初始化, Class.forName(className)默认是需要初始化。 一旦初始化,就会触发目标对象的 static块代码执行,static参数也也会被再次初始化。 ClassLoader.loadClass(className)方法,内部实际调用的方法是 ClassLoader.loadClass(className,false); 第2个 boolean参数,表示目标对象是否进行链接,false表示不进行链接,由上面介绍可以, 不进行链接意味着不进行包括初始化等一些列步骤,那么静态块和静态对象就不会得到执行 ~~~ # 数据库链接为什么使用Class.forName(className) JDBC Driver源码如下,因此使用Class.forName(classname)才能在反射回去类的时候执行static块 ~~~ static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } ~~~