ClassLoader和Class.forName

本文详细解释了Java中Class的加载过程,分为加载、连接(包括验证、准备和解析)及初始化三个阶段,并阐述了Class.forName与ClassLoader.loadClass两种方法的主要区别。前者会在加载后立即初始化,后者仅完成加载但不进行链接。

Class的装载分了三个阶段,loading(加载),linking(在这个过程中,又包括了验证,准备和解析三个阶段)和initializing(初始化),分别定义在The Java Language Specification的12.2,12.3和12.4。

在源码中,可以发现,实际上Class.forName(className) 是调用Class.forName(className, true, this.getClass().getClassLoader())。注意第二个参数,是指Class被loading后是不是必须被初始化。

ClassLoader.loadClass(className)实际上调用的是ClassLoader.loadClass(name, false),第二个参数指出Class是否被link。

这就是这两者最为主要的区别。
Class.forName(className)装载的class已经被初始化,而ClassLoader.loadClass(className)装载的class还没有被link。

一般情况下,这两个方法效果一样,都能装载Class。但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。

例如,在JDBC编程中,常看到这样的用法,Class.forName(“com.mysql.jdbc.Driver”),如果换成了 getClass().getClassLoader().loadClass(“com.mysql.jdbc.Driver”),就不行。
为什么呢?打开com.mysql.jdbc.Driver的源代码看看,

// Register ourselves with the DriverManager
//
static {
    try {
        java.sql.DriverManager.registerDriver(new Driver());
    } catch (SQLException E) {
        throw new RuntimeException("Can't register driver!");
    }
}

原来,Driver在static块中会注册自己到java.sql.DriverManager。而static块就是在Class的初始化中被执行。所以这个地方就只能用Class.forName(className)。

Class.forName() ClassLoader.loadClass()Java 中用来加载类的两种方法,它们在使用场合内部细节上存在一些重要区别: - **功能与默认行为**:Class.forName() 是静态方法,用于加载类并自动初始化它,即执行静态初始化块静态变量的赋值;而 ClassLoader.loadClass()ClassLoader 类的实例方法,默认不会自动初始化类,除非调用其他相关方法,只有在 newInstance 时才会执行 static 块 [^1][^3]。 - **调用方式**:Class.forName() 为静态方法,调用时直接通过类名调用;ClassLoader.loadClass() 是实例方法,需先获取 ClassLoader 实例,再调用该方法 [^1]。 - **使用场景**:Class.forName() 更简单,适合大多数情况,常用于动态加载类,特别是在需要实例化某个类而类名在编译时未知、或从配置文件中读取类名的场景;ClassLoader.loadClass() 提供更细粒度的控制,适合自定义类加载场景,如自定义类加载器时,或需要分离加载初始化逻辑的情况 [^1]。 - **方法本质**:Class.forName(className) 实际调用的是 Class.forName(className, true, classloader) 方法,第二个 boolean 参数为 true 表示在找到类后必须初始化;ClassLoader.loadClass(className) 实际调用的是 ClassLoader.loadClass(className, false) 方法,第二个 boolean 参数为 false 表示对象被装载后不进行链接,自然也就不会进行到初始化这一步 [^2]。 以下是两者的代码示例: ```java // Class.forName() 示例 try { // 动态加载并初始化类 Class<?> cls = Class.forName("com.example.MyClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // ClassLoader.loadClass() 示例 try { ClassLoader classLoader = MyClass.class.getClassLoader(); // 加载类但不初始化它 Class<?> cls = classLoader.loadClass("com.example.MyClass"); // 更晚才进行初始化 } catch (ClassNotFoundException e) { e.printStackTrace(); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值