本文来说下Class.forName 和 ClassLoader 有什么区别

文章目录

  • 概述
  • 实例测试
  • 应用场景
  • 本文小结

概述

在 java 中 Class.forName() 和 ClassLoader 都可以对类进行加载。ClassLoader 就是遵循双亲委派模型最终调用启动类加载器的类加载器,实现的功能是“通过一个类的全限定名来获取描述此类的二进制字节流”,获取到二进制流后放到 JVM 中。Class.forName() 方法实际上也是调用的 CLassLoader 来实现的

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

/**
Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to:
Class.forName(className, true, currentLoader)
where currentLoader denotes the defining class loader of the current class.
For example, the following code fragment returns the runtime Class descriptor for the class named java.lang.Thread:
Class t = Class.forName("java.lang.Thread")
A call to forName("X") causes the class named X to be initialized.
Params:
className – the fully qualified name of the desired class.
Returns:
the Class object for the class with the specified name.
Throws:
LinkageError – if the linkage fails
ExceptionInInitializerError – if the initialization provoked by this method fails
ClassNotFoundException – if the class cannot be located
**/@CallerSensitive
public static Class<?> forName(String className)throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

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

也可以调用 Class.forName(String name, boolean initialize,ClassLoader loader) 方法来手动选择在加载类的时候是否要对类进行初始化。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. Given the fully qualified name for a class or interface (in the same format returned by getName) this method attempts to locate, load, and link the class or interface. The specified class loader is used to load the class or interface. If the parameter loader is null, the class is loaded through the bootstrap class loader. The class is initialized only if the initialize parameter is true and if it has not been initialized earlier.
If name denotes a primitive type or void, an attempt will be made to locate a user-defined class in the unnamed package whose name is name. Therefore, this method cannot be used to obtain any of the Class objects representing primitive types or void.
If name denotes an array class, the component type of the array class is loaded but not initialized.
For example, in an instance method the expression:
Class.forName("Foo")
is equivalent to:
Class.forName("Foo", true, this.getClass().getClassLoader())
Note that this method throws errors related to loading, linking or initializing as specified in Sections 12.2, 12.3 and 12.4 of The Java Language Specification. Note that this method does not check whether the requested class is accessible to its caller.
If the loader is null, and a security manager is present, and the caller's class loader is not null, then this method calls the security manager's checkPermission method with a RuntimePermission("getClassLoader") permission to ensure it's ok to access the bootstrap class loader.
Params:
name – fully qualified name of the desired class
initialize – if true the class will be initialized. See Section 12.4 of The Java Language Specification.
loader – class loader from which the class must be loaded
Returns:
class object representing the desired class
Throws:
LinkageError – if the linkage fails
ExceptionInInitializerError – if the initialization provoked by this method fails
ClassNotFoundException – if the class cannot be located by the specified class loader
Since:
1.2
See Also:
forName(String), ClassLoader
**/@CallerSensitivepublic 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);}

实例测试

下面还是举例来说明结果吧:一个含有静态代码块、静态变量、赋值给静态变量的静态方法的类。

package cn.yiyiyun.pre.app.handle.test;public class ClassForName {//静态代码块static {System.out.println("执行了静态代码块");}//静态变量private static String staticFiled =staticMethod();//赋值静态变量的静态方法public static String staticMethod() {System.out.println("执行了静态方法");return "给静态字段赋值了";}}

测试方法:

package cn.yiyiyun.pre.app.handle.test;public class Main {public static void main(String[] args) {try {Class.forName("cn.yiyiyun.pre.app.handle.test.ClassForName");System.out.println("#########分割符(上面是class.forName的加载过程,下面是ClassLoader的加载过程)##########");ClassLoader.getSystemClassLoader().loadClass("cn.yiyiyun.pre.app.handle.test.ClassForName");} catch (ClassNotFoundException e) {e.printStackTrace();}}}

程序结果

根据运行结果得出 Class.forName 加载类是将类进了初始化,而 ClassLoader 的 loadClass 并没有对类进行初始化,只是把类加载到了虚拟机中


应用场景

在我们熟悉的 Spring 框架中的 IOC 的实现就是使用的 ClassLoader。而在我们使用 JDBC 时通常是使用 Class.forName() 方法来加载数据库连接驱动。这是因为在 JDBC 规范中明确要求 Driver(数据库驱动)类必须向 DriverManager 注册自己。

以 MySQL 的驱动为例解释:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package com.mysql.cj.jdbc;import java.sql.DriverManager;
import java.sql.SQLException;public class Driver extends NonRegisteringDriver implements java.sql.Driver {public Driver() throws SQLException {}static {try {DriverManager.registerDriver(new Driver());} catch (SQLException var1) {throw new RuntimeException("Can't register driver!");}}
}

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


本文小结

本文详细介绍了Class.forName和ClassLoader之间的区别的和联系,对于更加深入的理解类加载相关的知识与内容是十分有好处的。

Class.forName和ClassLoader有什么区别相关推荐

  1. 面试题:Class.forName 和 ClassLoader 有什么区别?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:http://t.cn/AiQQ7dwi 在 java 中 ...

  2. 反射中Class.forName()和ClassLoader.loadClass()的区别

    一 Java类装载过程 装载:通过累的全限定名获取二进制字节流,将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lang.class对象: 链接:执行下面的校验.准备和解析步骤,其 ...

  3. 获取第二个匹配class_面试题:Class.forName 和 ClassLoader 有什么区别?

    来源:http://t.cn/AiQQ7dwi 在 java 中 Class.forName() 和 ClassLoader 都可以对类进行加载.ClassLoader 就是遵循双亲委派模型最终调用启 ...

  4. 面试题鬼的很:Class.forName 和 ClassLoader 有什么区别?

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"加群"加入公众号专属技术群 来源 | http://rrd.me/eW9gG 在 ja ...

  5. 面试官 | Class.forName 和 ClassLoader 有什么区别?

    作者 | 纪莫 来源 | dwz.date/eUc 在 Java 中 Class.forName() 和 ClassLoader 都可以对类进行加载.ClassLoader 就是遵循双亲委派模型最终调 ...

  6. 【重难点】【JVM 02】反射在 JVM 层面的实现流程、Class.forName() 和 ClassLoader.loadClass 的区别

    [重难点][JVM 02]反射在 JVM 层面的实现流程.Tomcat 的请求流程和 JVM 的类加载情况 文章目录 [重难点][JVM 02]反射在 JVM 层面的实现流程.Tomcat 的请求流程 ...

  7. Class.forName 和 ClassLoader 到底有啥区别?

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者 | 纪莫 来源 | https://www.cnblogs. ...

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

    前言 最近在面试过程中有被问到,在Java反射中Class.forName()加载类和使用ClassLoader加载类的区别.当时没有想出来后来自己研究了一下就写下来记录一下. 解释 在java中Cl ...

  9. class mywnd : pubic qwidget是什么意思_学了这么久java反射,你知道class.forName和classloader的区别吗?...

    前两天头条有朋友留言说使用class.forName找不到类,可以使用classloader加载.趁此机会总结一下,正好看到面试中还经常问到. 一.类加载机制 上面两种加载类的方式说到底还是为了加载一 ...

最新文章

  1. aa bb ccc java,TinyTemplate(Velocity Plus版)即将火热推出~~~
  2. Java线程--BlockingQueue使用
  3. Java单例模式实现(线程安全)
  4. arm开发板挂载win10和ubuntu haneWIN NFS Server
  5. AMOS分析技术:软件安装及菜单功能介绍;这次是视频教程
  6. 对目录的操作(opendir)
  7. 手机编写java的软件_手机上可以用来学习编程的软件有哪些?
  8. android模拟器录制视频教程,畅玩安卓模拟器怎么录制视频?畅玩模拟器录制游戏视频图文教程...
  9. 如何用Excel快速制作甘特图?(超详细!)
  10. 家庭影院是什么?为什么选择家庭影院?
  11. 极速办公(excel)身份证中的出生日期如何提取
  12. 世界顶级机器学习科学家黄恒加入京东,出任京东大数据首席科学家
  13. 电脑出现“选择一个选项” 只有关闭和疑难解答
  14. OpenCore 版本升级后清除NVRAM
  15. js中的trim函数怎么使用
  16. tcpdump抓包使用小结
  17. Go语言map的并发操作
  18. 2021-12-23 迈向程序员的第五十二步
  19. 思科Cisco交换机的基本命令
  20. 春华秋实,匠心育人——北大青鸟职业教育2022年教学研讨交流会(北京会场)圆满举行

热门文章

  1. PHP生成缩略图(2)--等比缩略图
  2. 走近伏羲,谈5000节点集群调度与性能优化
  3. jquery autocomplete的使用
  4. vue+uwsgi+nginx部署路飞学城
  5. VirtualBox下安装MacOS11
  6. 原生js-Ajax jq-Ajax集结
  7. Docker 容器的运行(八)
  8. 【云栖大会】阿里妈妈:数字营销“智”变
  9. 何时使用hadoop fs、hadoop dfs与hdfs dfs命令(转)
  10. [转]配置nginx+apache 其中动态由apache处理,静态由nginx处理