Class.forName()方法详解

本文深入解析Java中的Class类,介绍其获取方式、常用方法及使用技巧。探讨Class类的加载机制,newInstance()与new关键字的区别,以及Class.forName()在实际项目中的应用场景。
部署运行你感兴趣的模型镜像

1、Class类简介:


 Java程序在运行时,Java运行时系统一直对所有的对象进行所谓的运行时类型标识。这项信息纪录了每个对象所属的类。虚拟机通常使用运行时类型信息选准正确方法去执行,用来保存这些类型信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。
      Class 没有公共构造方法。Class 对象是在加载类时由Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。 
      虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
      基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。 
      每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
      一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。

一、如何得到Class的对象呢?有三种方法可以的获取:

  1、调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法。例如:
    MyObject x;
    Class c1 = x.getClass();

 2、使用Class类的中静态forName()方法获得与字符串对应的Class对象。例如: 
    Class c2=Class.forName("MyObject"),Employee必须是接口或者类的名字。

3、获取Class类型对象的第三个方法非常简单。如果T是一个Java类型,那么T.class就代表了匹配的类对象。例如
    Class cl1 = Manager.class;
    Class cl2 = int.class;
    Class cl3 = Double[].class;
    注意:Class对象实际上描述的只是类型,而这类型未必是类或者接口。例如上面的int.class是一个Class类型的对象。由于历史原因,数组类型的getName方法会返回奇怪的名字。

二、Class类的常用方法

1、getName() 

一个Class对象描述了一个特定类的属性,Class类中最常用的方法getName以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。

2、newInstance()

Class还有一个有用的方法可以为类创建一个实例,这个方法叫做newInstance()。例如:
    x.getClass.newInstance(),创建了一个同x一样类型的新实例。newInstance()方法调用默认构造器(无参数构造器)初始化新建对象。

3、getClassLoader() 

返回该类的类加载器。

   4、getComponentType() 
    返回表示数组组件类型的 Class。

   5、getSuperclass() 
    返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。

   6、isArray() 
    判定此 Class 对象是否表示一个数组类。

三、Class的一些使用技巧

1、forName和newInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例如
    Object obj = Class.forName(s).newInstance();

2、虚拟机为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。例如:
    if(e.getClass() == Employee.class)...

2、 Class.forName()方法:


Class.forName返回与给定的字符串名称相关联接口的Class对象。

Class.forName是一个静态方法,同样可以用来加载类。该方法有两种形式:Class.forName(String name, boolean initialize, ClassLoader loader)和 Class.forName(String className)。第一种形式的参数 name表示的是类的全名;initialize表示是否初始化类;loader表示加载时使用的类加载器。第二种形式则相当于设置了参数 initialize的值为 true,loader的值为当前类的类加载器。

static Class<?>

forName(String className)

Returns the Class object associated with the class or interface with the given string name.

static Class<?>

forName(String name, boolean initialize, ClassLoader loader)

Returns the Class object associated with the class or interface with the given string name, using the given class loader.

说明:

publicstatic Class<?> forName(String className)

Returns the Class object associated withthe class or interface with the given string name. Invokingthis method is equivalent to:

Class.forName(className,true, currentLoader)

where currentLoader denotes the definingclass loader of the current class.

For example, thefollowing code fragment returns the runtime Class descriptor for theclass named java.lang.Thread:

Class t =Class.forName("java.lang.Thread")

A call to forName("X") causes theclass named X to beinitialized.

Parameters:

className - the fully qualifiedname of the desired class.

Returns:

the Class object for the classwith the specified name.

从官方给出的API文档中可以看出:

Class.forName(className)实际上是调用Class.forName(className,true, this.getClass().getClassLoader())。第二个参数,是指Class被loading后是不是必须被初始化。可以看出,使用Class.forName(className)加载类时则已初始化。

所以Class.forName(className)可以简单的理解为:获得字符串参数中指定的类,并初始化该类

 

 一.首先你要明白在java里面任何class都要装载在虚拟机上才能运行。

1.      forName这句话就是装载类用的(new是根据加载到内存中的类创建一个实例,要分清楚)。 

2.      至于什么时候用,可以考虑一下这个问题,给你一个字符串变量,它代表一个类的包名和类名,你怎么实例化它?

           A a = (A)Class.forName("pacage.A").newInstance();这和 A a =new A();是一样的效果。

3.      jvm在装载类时会执行类的静态代码段,要记住静态代码是和class绑定的,class装载成功就表示执行了你的静态代码了,而且以后不会再执行这段静态代码了。

4.      Class.forName(xxx.xx.xx)的作用是要求JVM查找并加载指定的类,也就是说JVM会执行该类的静态代码段。

5.      动态加载和创建Class 对象,比如想根据用户输入的字符串来创建对象

       String str = 用户输入的字符串  

       Class t = Class.forName(str);  

       t.newInstance(); 

 二.在初始化一个类,生成一个实例的时候,newInstance()方法和new关键字除了一个是方法,一个是关键字外,最主要有什么区别?

      1.它们的区别在于创建对象的方式不一样,前者是使用类加载机制,后者是创建一个新类。

      2.那么为什么会有两种创建对象方式?

        这主要考虑到软件的可伸缩、可扩展和可重用等软件设计思想。  
        Java中工厂模式经常使用newInstance()方法来创建对象,因此从为什么要使用工厂模式上可以找到具体答案。例如:

           class c = Class.forName(“Example”);  

           factory = (ExampleInterface)c.newInstance();  

       其中ExampleInterface是Example的接口,可以写成如下形式:

          String className = "Example";  

          class c = Class.forName(className);  

          factory = (ExampleInterface)c.newInstance();  

      进一步可以写成如下形式:

          String className = readfromXMlConfig;//从xml 配置文件中获得字符串

         class c = Class.forName(className);  

         factory = (ExampleInterface)c.newInstance();  

        上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。  
        3.从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。  但是使用newInstance()方法的时候,

         就必须保证:

              1、这个类已经加载;

              2、这个类已经连接了。

        而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java API的那个加载器。  
         现在可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好

         的灵活性,提供给了一种降耦的手段。  

三.最后用最简单的描述来区分new关键字和newInstance()方法的区别: 

1. newInstance: 弱类型。低效率。只能调用无参构造。  
         2. new: 强类型。相对高效。能调用任何public构造。

3、应用情景:


情景一:加载数据库驱动的时候

Class.forName的一个很常见的用法是在加载数据库驱动的时候。

如:

[java]  view plain  copy
 print ?
  1. Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");  
  2. Connection con=DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName==JSP","jph","jph");      

  为什么在我们加载数据库驱动包的时候有的却没有调用newInstance( )方法呢?

即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢? 

刚才提到,Class.forName("");的作用是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码段。

而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBCDriver的Driver类的代码都必须类似如下: 
          public classMyJDBCDriver implements Driver {

    static{

       DriverManager.registerDriver(new MyJDBCDriver());

   }

   } 

  既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

情景二:使用AIDL与电话管理Servic进行通信

Method method =Class.forName("android.os.ServiceManager")

         .getMethod("getService",String.class);

// 获取远程TELEPHONY_SERVICEIBinder对象的代理

IBinder binder =(IBinder) method.invoke(null, new Object[] { TELEPHONY_SERVICE});

// IBinder对象的代理转换为ITelephony对象

ITelephonytelephony = ITelephony.Stub.asInterface(binder);

// 挂断电话

telephony.endCall();

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

<think>我们正在讨论Java中的Class.forName方法。根据引用[1],Class.forName是Java反射机制中的重要方法,用于动态加载类并初始化类的字节码。它在框架开发和底层实现中常见,如JDBC驱动加载和动态代理。 引用[2]指出,Class.forName(xxx)返回的是一个类,调用.newInstance()后才会创建一个对象。它的作用是要求JVM查找并加载指定的类,并且会执行该类的静态代码段。 引用[3]强调,Class.forName用于装载类,而new是根据加载到内存中的类创建一个实例。它常用于需要根据字符串变量(代表类的全限定名)来实例化对象的情况。 引用[4]补充了细节:Class.forName(String name)生成指定类名的类对象(Class对象),等同于Class.forName(className, true, currentLoader),其中第二个参数true表示会进行类的初始化(即执行静态代码块)。同时,它描述了类加载过程:通过全限定名获取类的二进制字节流,并将字节流转化为方法区的运行时数据结构。特别提到,生成Class对象后,会执行静态块代码,如MySQL驱动的加载。 因此,我们可以总结: 1. Class.forName的主要作用是动态加载类到JVM中,并返回一个Class对象。 2. 在加载过程中,如果指定了初始化(默认情况),则会执行该类的静态初始化块(static块)和静态变量的初始化。 3. 通常,我们使用它来加载那些在编译时无法确定,但在运行时通过字符串形式给出的类。 下面,我将详细解释Class.forName的含义、使用方法和注意事项,并给出代码示例。 ### 1. Class.forName的基本用法 `Class.forName` 是一个静态方法,它有两种重载形式: - `Class<?> forName(String className)` - `Class<?> forName(String name, boolean initialize, ClassLoader loader)` 我们常用的是第一种形式,它等同于 `Class.forName(className, true, currentLoader)`,即会进行初始化(执行静态块),并使用当前类的类加载器。 示例:加载一个类并执行其静态块 ```java public class Test { static { System.out.println("静态初始化块执行"); } } public class Main { public static void main(String[] args) throws ClassNotFoundException { Class<?> clazz = Class.forName("Test"); } } ``` 运行Main类,输出:"静态初始化块执行"。 ### 2. 为什么需要Class.forName? 在Java中,类是在第一次使用时动态加载的。通常,我们通过new关键字创建一个对象时,类会被加载。但有时我们无法在编译时知道具体的类名,而是通过字符串形式在运行时获取。例如: - 数据库驱动加载:在JDBC中,我们使用`Class.forName("com.mysql.cj.jdbc.Driver")`来加载驱动,驱动的静态块中会向DriverManager注册自己。 - 框架中根据配置文件的类名动态加载类(如Spring框架的IoC容器)。 ### 3. 与newInstance()结合创建对象 通过Class.forName获得Class对象后,我们可以调用`newInstance()`方法来创建该类的实例(要求类必须有一个无参构造器): ```java Class<?> clazz = Class.forName("com.example.MyClass"); Object obj = clazz.newInstance(); // 相当于调用无参构造器 ``` 注意:从Java 9开始,`newInstance()`方法被标记为过时,推荐使用`clazz.getDeclaredConstructor().newInstance()`。 ### 4. 关于初始化 当我们使用`Class.forName(className, false, loader)`时,第二个参数为false,则不会执行静态初始化块。这在某些特殊场景下有用,比如我们只需要加载类而不希望触发静态块。 ### 5. 注意事项 - 类名必须是全限定名(包含包名),例如`java.lang.String`。 - 该方法会抛出`ClassNotFoundException`,因此需要处理异常。 - 初始化静态块时,如果静态块中有复杂的操作或异常,可能会导致加载失败。 ### 6. 代码示例:JDBC驱动加载 在JDBC中,我们通常这样加载驱动: ```java Class.forName("com.mysql.cj.jdbc.Driver"); ``` 这是因为在`Driver`类中有一个静态初始化块: ```java 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!"); } } // ... } ``` 当调用`Class.forName`时,静态块执行,将驱动注册到`DriverManager`中。 ### 总结 `Class.forName` 是Java反射机制中用于动态加载类的方法,它会执行类的静态初始化块(默认情况下)。主要应用场景包括: - 动态加载类(尤其当类名来自配置、字符串变量时) - 框架开发(如JDBC驱动加载、动态代理等) 但要注意,它只加载类并初始化静态部分,创建对象需要另外调用`newInstance()`(或通过构造器)。 §§相关问题§§ 1. Java中Class.forNameClassLoader.loadClass有什么区别? 2. 为什么JDBC驱动加载需要用Class.forName? 3. Java反射中,除了Class.forName,还有哪些方式可以获取Class对象? 4. Class.forName在加载类时会触发哪些类加载阶段? </think>### Java 中 `Class.forName()` 的含义详解 `Class.forName()` 是 **Java 反射机制的核心方法**,用于动态加载并初始化类的字节码。以下是其核心含义和原理: #### 一、核心作用 1. **动态加载类** 根据**字符串形式的全限定类名**(如 `"java.lang.String"`)查找并加载该类到 JVM 中,返回对应的 `Class` 对象[^1][^2]。 ```java Class<?> clazz = Class.forName("com.example.MyClass"); // 加载类 ``` 2. **触发类初始化**(默认行为) 默认情况下(即 `Class.forName(className)`),会**执行类的静态初始化块(static 代码块)和静态变量赋值**[^2][^4]。 例如 JDBC 驱动注册: ```java Class.forName("com.mysql.cj.jdbc.Driver"); // 触发 Driver 类中的 static { DriverManager.registerDriver(new Driver()); } ``` 3. **与 `new` 关键字的区别** - `Class.forName()` 仅**加载类并初始化静态成员**,但不创建对象实例[^2][^3]。 - 创建对象需额外调用 `clazz.newInstance()`(已废弃)或 `clazz.getConstructor().newInstance()`: ```java Object obj = clazz.getDeclaredConstructor().newInstance(); // 创建实例 ``` --- #### 二、关键参数解析 方法签名: `Class<?> forName(String name, **boolean initialize**, ClassLoader loader)` - **`initialize` 参数**(默认为 `true`) - `true`:执行类的静态初始化(static 块)[^4]。 - `false`:仅加载类到内存,**不执行静态初始化**(适用于避免副作用场景)。 - **`ClassLoader` 参数** 指定类加载器,默认使用当前类的加载器。 --- #### 三、典型应用场景 1. **JDBC 驱动加载** 通过静态块自动向 `DriverManager` 注册驱动[^1]: ```java Class.forName("com.mysql.cj.jdbc.Driver"); // 静态块中注册驱动 ``` 2. **动态扩展功能** 根据配置文件动态加载实现类(如插件化架构): ```java String className = config.getProperty("serviceImpl"); Service service = (Service) Class.forName(className).newInstance(); ``` 3. **框架开发** Spring、Hibernate 等框架利用此方法实现依赖注入和动态代理[^1]。 --- #### 四、注意事项 1. **必须处理 `ClassNotFoundException`** 当类不存在时抛出该异常: ```java try { Class<?> clazz = Class.forName("InvalidClassName"); } catch (ClassNotFoundException e) { // 处理找不到类的情况 } ``` 2. **性能影响** 反射操作比直接调用慢,高频场景需谨慎使用。 3. **替代 `newInstance()`** Java 9+ 推荐使用构造器创建实例: ```java Object obj = clazz.getDeclaredConstructor().newInstance(); ``` --- ### 总结 | **核心特性** | **说明** | |----------------------|--------------------------------------------------------------------------| | **动态加载** | 通过字符串类名加载类到 JVM | | **触发静态初始化** | 默认执行 static 代码块(可通过 `initialize=false` 关闭) | | **返回 Class 对象** | 获取类元信息(方法、字段等),为反射操作提供入口 | | **与实例化分离** | 加载类 ≠ 创建对象,需额外调用构造器 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值