• 【Java面试】反射中,Class.forName和classloader的区别是什么?


    java中class.forName()和classLoader都可用来对类进行加载。
    class.forName()前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static
    块。
    而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在
    newInstance才会去执行static块。
    这就是为什么手写对JDBC的驱动加载的使用我们一般选用forName,可以看到Driver的加载代码是放在静态代码块中的。
    在这里插入图片描述
    Class.forName(name, initialize, loader)带参函数也可控制是否加载static块。并且只有调用了
    newInstance()方法才会调用构造函数,创建类的对象。
    看下Class.forName()源码
    在这里插入图片描述

    //Class.forName(String className) 这是1.8的源码
    public static Class<?> forName(String className) throws
    ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller),
    caller);
    }
    //注意第二个参数,是指Class被loading后是不是必须被初始化。 
    //不初始化就是不执行static的代码即静态代码
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    然后就是,测试代码证明上面的结论是OK的,如下:

    package com.lxk.Reflect;
    /**
    * Created by lxk on 2017/2/21
    */
    public class Line {
    static {
    System.out.println("静态代码块执行:loading line");
    }
    }
    package com.lxk.Reflect;
    /**
    * Created by lxk on 2017/2/21
    */
    public class Point {
    static {
    System.out.println("静态代码块执行:loading point");
    }
    }
    package com.lxk.Reflect;
    /**
    * Class.forName和classloader的区别
    * 

    * Created by lxk on 2017/2/21 */ public class ClassloaderAndForNameTest { public static void main(String[] args) { String wholeNameLine = "com.lxk.Reflect.Line"; String wholeNamePoint = "com.lxk.Reflect.Point"; System.out.println("下面是测试Classloader的效果"); testClassloader(wholeNameLine, wholeNamePoint); System.out.println("----------------------------------"); System.out.println("下面是测试Class.forName的效果"); testForName(wholeNameLine, wholeNamePoint); } /** * classloader */ private static void testClassloader(String wholeNameLine, String wholeNamePoint) { Class<?> line; Class<?> point; ClassLoader loader = ClassLoader.getSystemClassLoader(); try { line = loader.loadClass(wholeNameLine); point = loader.loadClass(wholeNamePoint); //demo = ClassloaderAndForNameTest.class.getClassLoader().loadClass(wholeNamePoint);//这个 也是可以的 System.out.println("line " + line.getName()); System.out.println("point " + point.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * Class.forName */ private static void testForName(String wholeNameLine, String wholeNamePoint) { try { Class line = Class.forName(wholeNameLine); Class point = Class.forName(wholeNamePoint); System.out.println("line " + line.getName()); System.out.println("point " + point.getName()); } catch (Exception e) { e.printStackTrace(); } } }

    • 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
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69

    执行结果如下:
    备注
    根据运行结果,可以看到,classloader并没有执行静态代码块,如开头的理论所说。
    而下面的Class.forName则是夹在完之后,就里面执行了静态代码块,可以看到,2个类,line和point的静态代码块执行结果是一起的,然后才是各自的打印结果。也说明上面理论是OK的。
    当然,如果要加载的类中有静态成员变量,并且还调用了某个静态方法,那么这个静态方法也会被调用以便给静态成员变量赋值。比如下面这样
    在这里插入图片描述

  • 相关阅读:
    OS 进程同步
    野火A7学习第一次(简介和学习计划)
    【译】32位 .NET Framework 项目的 WinForm 设计器选择
    科技与时尚共进化,优衣库以硬实力创造品牌长期价值
    Vue前端框架08 Vue框架简介、VueAPI风格、模板语法、事件处理、数组变化侦测
    LeetCode209——长度最小的子数组
    智能计量插座多角色定位:用电监测&资产管理的智能化强大运用
    搞懂SpringBean生命周期与依赖注入:你还在为这些热门技术感到困惑吗?Comate插件来帮你解答!
    Oracle中instr,rtrim,XMLPARSE,XMLAGG,GETCLOBVAL函数的使用
    利用ChatGPT进行数据分析并生成数据分析报告
  • 原文地址:https://blog.csdn.net/Zhangsama1/article/details/128077092