Java反射中,为什么推荐Class.forName()获取class?

一、Java反射中获取Class对象的三种方式

在Java反射中,反射的入口就是class,获取class的方式有三种

  1. Class.class;
  2. Class.forName();
  3. 对象.getClass()

对三者的简单理解

  1. Class.class的形式会使JVM使用类加载器将类装入内存(前提是类还没有装入内存),不做类的初始化工作,返回Class对象。
  2. Class.forName()的形式会装入类并做类的静态初始化,返回Class对象。
  3. 对象.getClass的形式会对类进行静态初始化、非静态初始化,返回引用运行时真正所指的对象(因为子对象的引用可能会赋给父对象的引用变量中)所属的类的Class对象。

静态初始化是指在加载类的时候初始化,而非静态初始化是new对象的时候初始化。

三种情况在生成Class对象的时候都会判断内存中是否已经加载此类。

注:只有使用Class.forName()时才会进行异常处理,因为Class.forName()要加载类路径,避免找不到的情况发生。

二、Class.forName源码分析

Class.forName(String className);这个方法的源码是

@CallerSensitive
public static Class<?> forName(String className) throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

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

可以清楚的看到Class.forName()方法实际上是调用ClassLoader来实现的。

ClassLoader是遵循双亲委派模型,调用启动类加载器的类加载器,实现的功能是“通过一个类的全限定名来获取描述此类的二进制字节流”,获取到二进制流后放到JVM中。

三、为什么推荐Class.forName()获取class?

Class.forName(),我相信我们第一次接触它的时候,大多数是在学习JDBC的时候。

使用JDBC时通常使用Class.forName()方法来加载数据库连接驱动。这是因为在JDBC规范中明确要求Driver(数据库驱动)类必须向DriverManager注册自己。

以MySQL的驱动为例解释:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {  

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

通过源码可以看出Driver注册到DriverManager中的操作写在了静态代码块中,这就是为什么在写JDBC时使用Class.forName()的原因。

Class.forName()在加载数据库驱动时,是一种破坏双亲委派机制的使用,通过Application ClassLoader来加载一个第三方类,并没有使用父级的Bootstrap ClassLoad加载器。

总之一句话,推荐使用Class.forName()方法获取Class的最重要原因就是Class.forName()方法做了类的静态初始化(Class.class方法没有进行类的静态初始化;对象.getClass()方法虽然也做了静态初始化,但还需要new一个对象出来,不是很方便)。

 

 

参考:

简单谈谈你对 Java 中 Class.forName()、Class.class、getClass() 三者的理解?

在Java的反射中,Class.forName和ClassLoader的区别

  • 7
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Class.forName() 方法是 Java 反射机制的一个方法,用于动态加载类。通过该方法可以在运行时加载指定的类,返回该类的 Class 对象。它通常用于加载数据库驱动程序或其他需要动态加载的类。例如,如果要加载名为 "com.example.MyClass" 的类,可以使用以下代码: ```java Class.forName("com.example.MyClass"); ``` 这将返回一个 Class 对象,可以用于创建该类的实例或访问其静态成员。 ### 回答2: Class.forName()是Java的一个静态方法,用于加载并返回指定类名的类对象。它的主要作用是动态地加载类,可以在运行时根据需要动态加载指定的类,而不需要在编译时就确定加载的类。 具体来说,Class.forName()方法的作用包括两个方面: 1. 加载类:Class.forName()方法会根据指定的类名来加载对应的类。它会在类路径下搜索并加载指定的类文件,将类的字节码加载到内存,并返回一个Class对象,表示该类在内存的表示。 2. 初始化类:在类加载过程Class.forName()方法会自动初始化被加载类的静态代码块和静态变量。该过程会执行被加载类的静态初始化代码,为类的静态变量分配内存空间,并为其赋予初始值。 需要注意的是,Class.forName()方法可以加载任意类型的类,包括普通的类、接口、抽象类,甚至是数组类。当指定的类名无法找到或加载时,该方法会抛出ClassNotFoundException异常。 Class.forName()方法常用于反射、数据库操作和框架开发等领域。在反射,该方法可以根据类名动态地创建和操作对象;在数据库操作,该方法可以加载数据库驱动程序,使得程序可以与数据库进行交互;在框架开发,该方法可以根据配置文件等动态加载不同的实现类。 总之,Class.forName()方法是Java一个重要的用于动态加载类的方法,能够在运行时加载指定的类,并对其进行初始化。它为Java的灵活性和动态性提供了重要的支持。 ### 回答3: Class.forName()是Java语言的一个方法,用于加载并返回指定类名的Class对象。 在Java程序,当我们需要使用一个类时,需要先加载这个类的Class对象。Class.forName()方法可以实现动态加载类,即在程序运行时才加载指定的类。通过这个方法,我们可以根据类的名称获取对应的Class对象,然后再通过Class对象进行一系列的操作,例如实例化对象、调用方法等。 Class.forName()方法的具体使用方式为:Class.forName("类的全限定名")。调用这个方法时,它会将指定的类名传递给ClassLoader,ClassLoader会根据类名去搜索并加载类的字节码文件,最终返回对应的Class对象。 Class.forName()方法常用在需要在运行时动态加载类的场景,例如使用反射机制时。通过Class.forName()方法,我们可以在运行时根据需要动态加载类,从而达到灵活使用不同的类的目的。另外,这个方法在一些框架也常被使用,用于实现插件化、模块化等特性。 需要注意的是,Class.forName()方法会触发类的初始化操作,即执行类的静态代码块和静态成员变量的初始化。如果只是希望加载类而不执行初始化操作,可以使用ClassLoader的loadClass()方法替代Class.forName()方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值