1.前言
JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化。下图是一个类在JVM中的完整生命周期,我们先重点关注类加载的五个部分。
通过Java连接mysql的时候,经常可以看到代码Class.forName("com.mysql.jdbc.Driver"), 那这句代码起到什么作用呢?我们带着这个疑问,继续往下看。
2.Class.ForName
Class.ForName返回与给定的字符串名称相关联类或接口的Class对象,也就是进行类加载。我们直接上源码:
通过源码可以看出两个细节点:
- 加载出来的类会被初始化。
- 类加载器使用的是调用forName方法的调用者的类加载器。
3.ClassLoader.loadClass
通过指定类加载器对类进行加载,但不会对类进行连接和初始化。上源码:
通过源码可以看出,resolve为false,也就是说明不会对类进行连接和初始化。
4.测试用例
当类初始化时,其静态代码块会被执行;我们先准备一个需要被加载的类TestCase.java,如果TestCase的类被初始化了,它的静态代码块就会被执行。
public class TestCase {
static {
System.out.println("TestCase初始化");
}
}
Class.forName的测试代码:
public class LoadClassCase {
public static void main(String[] args) {
try {
System.out.println("-----Start Load Class-----");
Class.forName("com.newbie.loadClass.TestCase");
System.out.println("-----End Load Class-----");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Class.forName的测试结果:
如预期,TestCase类加载后,进行了初始化。
ClassLoader.loadClass的测试代码:
public class LoadClassCase {
public static void main(String[] args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
System.out.println("-----Start Load Class-----");
classLoader.loadClass("com.newbie.loadClass.TestCase");
System.out.println("-----End Load Class-----");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
ClassLoader.loadClass的测试结果:
也是如我们预期ClassLoader.loadClass加载类之后,没有进行初始化。
这个我给java的新手朋友们留个作业,我们知道Class.forName会进行初始化,如果我把上面的
Class.forName测试用例代码改成如下,也就是Class.forName连续被调用两次,请问输出会是什么?
public class LoadClassCase {
public static void main(String[] args) {
try {
System.out.println("-----Start Load Class-----");
Class.forName("com.newbie.loadClass.TestCase");
Class.forName("com.newbie.loadClass.TestCase");
System.out.println("-----End Load Class-----");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
5.分析com.mysql.jdbc.Driver
看完上面的测试用例,对于Class.forName("com.mysql.jdbc.Driver")的作用现在看是不是就比较明朗了,对com.mysql.jdbc.Drive进行初始化,调用它的静态代码块,实现对jdbc的驱动注册。
6.总结
Class.ForName与ClassLoader.loadClass都是可以对类进行加载,但他们有两个不同点:
- Class.ForName会对类进行连接初始化,ClassLoader.loadClass不会
- Class.ForName是用的调用者的类加载器,ClassLoader.loadClass就是ClassLoader的对象本身