You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中loadClass("全限定类名")与<ClassName>.class.getDeclaredConstructors的区别

Java中ClassLoader.loadClass()与直接使用.class的区别及代码分析

咱们先把ClassLoader.loadClass("全限定类名")和直接用.class获取构造方法的核心差异掰扯清楚,再一步步拆解示例代码的执行逻辑。

一、两者的核心区别

  • 类初始化时机不一样:
    • ClassLoader.loadClass()走的是*延迟加载(懒加载)*路子——它只会把类的元数据加载到JVM,但不会触发类的初始化(比如静态代码块、静态变量赋值这些逻辑都不会执行),只有当你第一次调用newInstance()创建实例,或者主动访问类的静态成员时,才会完成初始化。
    • 而直接写<ClassName>.class就不一样了,代码执行到这一行的时候,JVM会立刻完成类的加载、链接、初始化全流程,静态代码块啥的直接就跑起来了。
  • 类加载器的可控性不同:
    • ClassLoader.loadClass()可以指定用哪个类加载器来加载类,比如示例里用的是ClassloadersExample对应的应用类加载器,你要是自定义了类加载器,也能切换着用,灵活性拉满。
    • <ClassName>.class是JVM自动用加载当前类的类加载器来加载目标类,开发者没法手动指定其他加载器,属于“全自动”模式。
  • 异常类型有区别:
    • ClassLoader.loadClass()会抛出ClassNotFoundException,这是检查型异常,必须显式捕获或者在方法上声明抛出。
    • 用<ClassName>.class如果找不到类,会抛出NoClassDefFoundError,这属于运行时错误,不需要提前捕获。

二、示例代码的执行逻辑分析

先把示例里没写完的代码补全成合理的样子,方便咱们分析:

class testMe{ 
    static {
        System.out.println("testMe类初始化");
    }
    void show(){ 
        System.out.println("Hello"); 
    } 
} 
public class ClassloadersExample { 
    public static void main(String args[]) { 
        ClassLoader c = ClassloadersExample.class.getClassLoader(); //Line 1 
        try { 
            Class c1 = c.loadClass("test.testMe"); // Line 2 
            Constructor a[] = c1.getDeclaredConstructors(); 
            for (Constructor constructor : a) { 
                testMe m = (testMe)constructor.newInstance(); 
                m.show(); 
            } 
            Constructor con[] = testMe.class.getDeclaredConstructors(); // Line 6 
            for (Constructor constructor : con) {
                testMe m = (testMe)constructor.newInstance();
                m.show();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

接下来一步步看执行流程:

  1. Line 1:获取加载ClassloadersExample的类加载器,默认是应用类加载器(AppClassLoader),负责加载classpath下的类文件。
  2. Line 2:调用loadClass("test.testMe")加载testMe类,这一步只完成类的加载+链接,不会触发testMe的静态代码块,所以此时不会输出"testMe类初始化"。
  3. 遍历构造方法并实例化:调用c1.getDeclaredConstructors()拿到testMe的所有构造方法(这里只有默认无参构造),然后调用constructor.newInstance()创建实例——这一步会触发testMe的类初始化,所以第一次执行时会先输出"testMe类初始化",接着调用show()输出"Hello"。
  4. Line 6及后续:直接用testMe.class.getDeclaredConstructors()获取构造方法,这时候testMe已经在之前的实例化过程中完成了初始化,JVM不会重复执行类初始化逻辑。所以遍历构造方法创建实例时,只会直接调用show()输出"Hello",不会再输出静态代码块的内容。

⚠️ 注意:如果testMe实际所在的包不是test,Line2会抛出ClassNotFoundException,所以要确保全限定类名和实际包结构一致。

内容的提问来源于stack exchange,提问作者Neha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:11:50