面试题:Class.ForName和ClassLoader.loadClass的区别

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的对象本身
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值