java 反射 forname_反射中Class.forName()和classLoader的区别

在搞清楚两者之间区别前,我们来了解下类加载过程。

一、类加载过程

44c4ab91d65e2c1a5e8b96ef7237be0e.png

1、加载

通过一个类的全限定名来获取定义此类的二进制字节流。

将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。

在内存中生成一个代表这个类的Java.lang.class对象,作为方法区这个类的各种数据的访问入口。

2、验证

文件格式验证

元数据验证

字节码验证

符号引用验证

3、准备

准备阶段是正式为类变量(仅被static修饰的变量)分配内存并设置类变量初始值的阶段,这些变量所使用的内存都将在方法区中进行分配。注意,这里所说的初始值“通常情况”下是数据类型的零值,“特殊情况”下是初始化真实的值,即常量值(static final)。

4、解析

解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。注意,这个阶段不一定要有。

5、初始化

类初始化阶段是类加载过程的最后一步,真正开始执行类中定义的Java程序代码。初始化类中的所有类变量的赋值和静态语句块。

二、源码分析

1、JDK8中Class.forName()源码

@CallerSensitive

public static Class> forName(String className)

throws ClassNotFoundException {

Class> caller = Reflection.getCallerClass();

return forName0(className, true, ClassLoader.getClassLoader(caller), caller);

}

@CallerSensitive

public static Class> forName(String name, boolean initialize, ClassLoader loader)

throws ClassNotFoundException

{

Class> caller = null;

SecurityManager sm = System.getSecurityManager();

if (sm != null) {

// Reflective call to get caller class is only needed if a security manager

// is present. Avoid the overhead of making this call otherwise.

caller = Reflection.getCallerClass();

if (sun.misc.VM.isSystemDomainLoader(loader)) {

ClassLoader ccl = ClassLoader.getClassLoader(caller);

if (!sun.misc.VM.isSystemDomainLoader(ccl)) {

sm.checkPermission(

SecurityConstants.GET_CLASSLOADER_PERMISSION);

}

}

}

return forName0(name, initialize, loader, caller);

}

Class.forName(className)方法,内部实际调用的方法是forName0这个方法,在这个forName0方法中的第二个参数被默认设置为了true,这个参数代表是否对加载的类进行初始化,设置为true时会类进行初始化,代表会执行类中的静态代码块,以及对静态变量的赋值等操作。

当然,可以通过Class.forName(String name, boolean initialize,ClassLoader loader)方法来手动选择在加载类的时候是否要对类进行初始化。

2、JDK8中ClassLoader.loadClass()源码

public Class> loadClass(String name) throws ClassNotFoundException {

return loadClass(name, false);

}

ClassLoader.loadClass(className)方法,内部实际调用的方法是loadClass(name, false);

第2个 boolean参数,表示目标对象是否进行链接,false表示不进行链接,即不进行包括初始化等一些列步骤,那么静态块和静态对象就不会得到执行。

3、结论

所以Class.forName加载类是将类进了初始化,而ClassLoader的loadClass并没有对类进行初始化,只是把类加载到了虚拟机中。

三、应用场景

1、JDBC时通常是使用Class.forName()方法来加载数据库连接驱动。因为在JDBC规范中明确要求Driver(数据库驱动)类必须向DriverManager注册自己,而注册的操作都在静态代码块中。

2、Spring框架中的IOC的实现就是使用的ClassLoader。

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值