在java反射中 Class.forName和classLoader的区别

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

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

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

也可以调用Class.forName(String name, boolean initialize,ClassLoader loader)方法来手动选择在加载类的时候是否要对类进行初始化。Class.forName(String name, boolean initialize,ClassLoader loader)的源码如下:

源码中的注释只摘取了一部分,其中对参数initialize的描述是:if {@code true} the class will be initialized.意思就是说:如果参数为true,则加载的类将会被初始化。

举例

下面还是举例来说明结果吧:

一个含有静态代码块、静态变量、赋值给静态变量的静态方法的类

测试方法:

运行结果:

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

应用场景

在我们熟悉的Spring框架中的IOC的实现就是使用的ClassLoader。

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

以MySQL的驱动为例解释:

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

在我们熟悉的Spring框架中的IOC的实现就是使用的ClassLoader。

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

以MySQL的驱动为例解释:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

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

    // ~ Static fields/initializers 

    // --------------------------------------------- 

  

    // 

    // Register ourselves with the DriverManager 

    // 

    static

        try

            java.sql.DriverManager.registerDriver(new Driver()); 

        } catch (SQLException E) { 

            throw new RuntimeException("Can‘t register driver!"); 

        

    

  

    // ~ Constructors 

    // ----------------------------------------------------------- 

  

    /**

     * Construct a new driver and register it with DriverManager

     

     * @throws SQLException

     *             if a database error occurs.

     */

    public Driver() throws SQLException { 

        // Required for Class.forName().newInstance() 

    

}

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

好了,今天就写到这了,最近在面试,遇到了很多问题,也学习了不少,虽然很累,但是也让人成长了不少,毕竟面试就是一个脱皮的过程,会遇到各种企业各种面试官各种问题,各种场景。给自己加油吧,找一个最少能让自己干个几年的公司,别总是让我遇到工作了没多久公司就垮掉的这种就行了。要不我也很无奈啊。

相关文章

发表评论

Name*

邮箱*

网站 (请以 http://开头)

(*) 表示必填项

提交评论

2 条评论

  1. 高岩

    2018/08/09 下午 2:22

    请问这句话
    最后调用的方法是forName0这个方法,在这个forName0方法中的第二个参数被默认设置为了true,这个参数代表是否对加载的类进行初始化,设置为true时会类进行初始化,代表会执行类中的静态代码块,以及对静态变量的赋值等操作。
    这个值难道是跳过类加载第二步链接中的初始化步骤么?
    但是我自己测试的时候设置这个参数为false的时候,静态的变量也完成了赋值操作啊,和值为true没有区别啊
    public class Test {
    public static void main(String[] args) throws Exception {
    System.out.println(“initialize…”);
    Class c = Class.forName(“TestStatic”, false, Test.class.getClassLoader());
    System.out.println(“1. i = ” + TestStatic.i);
    System.out.println(“instance…”);
    System.out.println(“2. i = ” + TestStatic.i);
    Object obj = c.newInstance();
    System.out.println(“end …”);
    }
    }
    public class TestStatic {
    static int i = 9;
    static {
    System.out.println(“*******************”);
    }
    }
    结果 1和2两处的i值都为9呢,如果跳过初始化步骤那么在链接的准备阶段应该会给i赋值int类型的默认值0的吧,所以1处应该是0,2处是9。请问这个是什么原因呢?

     0  0

    回复

    • 高岩

      2018/08/09 下午 2:25

      System.out.println(“2. i = ” + TestStatic.i);
      Object obj = c.newInstance();
      这两句顺序反了,不过结果还是一样的,都为9,

       0  0

      回复

? 编辑 SpringBoot | 第五章:多环境配置

SpringBoot | 第六章:常用注解介绍及简单使用 ?

0Java结合keytool实现非对称加密和解密

1Java连接HBase(kerberized集群)

2Java结合keytool实现非对称签名与验证

3高效遍历Java容器

4JDK源码阅读:ByteBuffer

5JDK源码阅读:InterruptibleChann...

最新评论

原文地址:https://www.cnblogs.com/lz81/p/9475952.html

时间: 2024-10-13 12:02:56

在java反射中 Class.forName和classLoader的区别的相关文章

Java反射中Class.forName与classLoader的区别

Java中的class.forName和classLoader都可以用来对类的加载. class.forName除了把类加载到JVM中,还会对类进行解释,执行类的static代码块: classLoader只是把类加载到JVM中,只有在调用newInstance的时候才会去执行static代码块: class.forName的源码如下,对static块的执行是可用控制的,第二个参数为True则执行 public static Class<?> forName(String className)

java反射中,Class.forName 和 ClassLoader 加载类的区别

解释 在java中Class.forName()和ClassLoader都可以对类进行加载.ClassLoader就是遵循双亲委派模型最终调用启动类加载器的类加载器,实现的功能是"通过一个类的全限定名来获取描述此类的二进制字节流",获取到二进制流后放到JVM中.Class.forName()方法实际上也是调用的CLassLoader来实现的 Class.forName(String className):这个方法的源码是 <tbody><tr><td cl

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

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

java反射中Class详解

package com.hey.reflect; /** * 1.万事万物皆对象,class类同样是Class类的实例对象,比如说一个Student类是Class的实例对象(类是对象,是java.lang.Class类的实例对象) * * 2.有三种方式获取一个类的类类型 * * 3.我们可以通过类的类类型,创建类的实例对象 * */public class ReflectDemo { public static void main(String[] args) { //Foo的实例对象怎么表示

Java 笔记之Class.forName与classloader

Class.forName返回的Class对象可以决定是否初始化.而ClassLoader.loadClass返回的类型绝对不会初始化,最多只会做连接操作.    Class.forName可以决定由哪个classLoader来请求这个类型.而ClassLoader.loadClass是用当前的classLoader去请求. JDBC的注册驱动基本都采用Class.forName. public static Class<?> forName(String name, boolean init

JAVA反射中的getFields()方法和getDeclaredFields ()方法的区别

关于获取类的字段有两种方式:getFields()和getDeclaredFields().我们先来看看这两者的区别吧: getFields():获得某个类的所有的公共(public)的字段,包括父类中的字段. getDeclaredFields():获得某个类的所有声明的字段,即包括public.private和proteced,但是不包括父类的申明字段. 同样类似的还有getConstructors()和getDeclaredConstructors().getMethods()和getDe

Java反射中的getClass()方法

Java反射学习 所谓反射,可以理解为在运行时期获取对象类型信息的操作.传统的编程方法要求程序员在编译阶段决定使用的类型,但是在反射的帮助下,编程人员可以动态获取这些信息,从而编写更加具有可移植性的代码.严格地说,反射并非编程语言的特性,因为在任何一种语言都可以实现反射机制,但是如果编程语言本身支持反射,那么反射的实现就会方便很多. 1,获得类型类 我们知道在Java中一切都是对象,我们一般所使用的对象都直接或间接继承自Object类.Object类中包含一个方法名叫getClass,利用这个方

Java反射中method.isBridge() 桥接方法

桥接方法是 JDK 1.5 引入泛型后,为了使Java的泛型方法生成的字节码和 1.5 版本前的字节码相兼容,由编译器自动生成的方法.我们可以通过Method.isBridge()方法来判断一个方法是否是桥接方法. 假定接口 public interface SuperClass<T> { void method(T t); } 它的一个实现类 public class AClass implements SuperClass<String> { @Override public

java反射中method类中的invoke方法作用

首先Method类代表一个方法,所以invoke(调用)就是调用Method类代表的方法.它可以让你实现动态调用,例如你可以动态的传人参数.下面是一个简单的例子. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class MethodTest {     public static void main(String[] args)