当前位置: 代码迷 >> 综合 >> 【jvm jdk】深入理解Java 反射中 Class.forName 和 ClassLoader 的区别
  详细解决方案

【jvm jdk】深入理解Java 反射中 Class.forName 和 ClassLoader 的区别

热度:39   发布时间:2024-02-27 15:20:31.0

文章目录

    • 1.简介
    • 2. Java类装载的步骤
    • 3. Class.forName
    • 4.ClassLoader

1.简介

Class.forName和ClassLoader都可以用来加载类,但是也有如下的区别:

  • Class.forName:除了将类的.class文件加载到jvm中之外,还会默认对类进行初始化,执行类中的静态代码块,以及对静态变量的赋值等操作
  • ClassLoader:将.class文件加载到jvm中,默认不会对类进行初始化,只有在newInstance才会去执行static块。

2. Java类装载的步骤

为了方便理解,我们简要介绍下类装载过程的步骤

  • 加载

    • 通过一个类的全限定名来获取定义此类的二进制字节流。
    • 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
    • 将类的class文件读入内存,并为之创建一个java.lang.Class对象,也就是说当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象, 作为方法区这个类的各种数据的访问入口。
  • 连接执行校验、准备和解析步骤,其中解析步骤是可选的

    • 校验检查加载的class文件的正确性和安全性
    • 准备为类变量分配存储空间并设置类变量初始值,类变量随类型信息存放在方法区中,生命周期很长,使用不当和容易造成内存泄漏。
    • 解析jvm将常量池内的符号引用转换为直接引用
  • 初始化:执行类变量赋值和静态代码块

3. Class.forName

Class.forName加载类时会将类进初始化

package com.test;public class Test {
    public static void main(String[] args) {
    try {
    Class c = Class.forName("com.test.DocTest");  //加载代码,并初始化System.out.println("-----------");  //分割线c.newInstance();   //new 一个对象} catch (Exception e) {
    e.printStackTrace();}}
}class DocTest {
    // 静态代码块static {
    System.out.println("执行了DocTest类的 静态代码块");}
}

JDK1.8 输出结果:

执行了DocTest类的 静态代码块    
-----------

我们发现DocTest 类的静态代码块是在new对象之前就执行的,说明加载该类时,也完成了初始化操作

4.ClassLoader

默认不会对类进行初始化,只有在newInstance才会去执行static块

package com.test;public class Test2 {
    public static void main(String[] args) {
    try {
    Class c = ClassLoader.getSystemClassLoader().loadClass("com.test.DocTest");System.out.println("-----------");c.newInstance();} catch (Exception e) {
    e.printStackTrace();}}
}

JDK1.8 输出结果:

-----------
执行了DocTest类的 静态代码块

参考:深入理解Java 反射中 Class.forName 和 ClassLoader 的区别 带例子

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

  相关解决方案