简单总结Class.forName(““).newinstance()和new()以及classLoader.loadClass(““)的区别

文章目录


声明:本文章仅供自己学习,其中引用了大量的其他笔者的优秀博文,如有侵权请告知,立即修改:邮箱 32248827@qq.om

背景

工作中需要将几个类进行实例化,可是这几个类不知道名字,希望动态加载,用了class.forname方法,前辈说最好用new()的方法,class.forname的方式比较耗性能,因为new的方式不能动态加载,所以要进行一次类名的判断,最好通过枚举类的方式,结合switch来进行判断,而不要用if else因为if else比较耗性能。

三种方法简单介绍

两种方式的共同作用将类进行实例化。

Class.forName(“”).newinstance()方式

Class clazz = Class.forName(“Apple”);//得到Apple的class对象。这个时候要去加载这个类到内存中Object apple =clazz.newInstance();//将class对象进行实例化。

new方式

Apple apple = new Apple();

classLoader.loadClass(“”)方式

Class clazz = classLoader.loadClass(“Apple”);Object apple =clazz.newInstance();

三种方法的区别

加载的时机可能不同

首先看一下类的加载机制
在这里插入图片描述
每个阶段所做的事情应该好好学习一下
类加载和new对象的过程:https://blog.csdn.net/qq_33824312/article/details/62858138

Class.forName(className)和ClassLoader.loadClass(className)的区别

通过阅读文章:https://blog.csdn.net/obession/article/details/78247165
引用一段话:
Class.forName(className)装载的class已经被初始化,而 ClassLoader.loadClass(className)装载的class还没有被link。一般情况下,这两个方法效果一样,都能装载Class。但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。
jdbc中的Class.forName(“com.mysql.jdbc.Driver”)
源码:

// Register ourselves with the DriverManagerstatic {try {java.sql.DriverManager.registerDriver(new Driver());} catch (SQLException E) {throw new RuntimeException(“Can’t register driver!”);}}

这段关键的代码是在类的加载中link过程进行的,即加载static代码块,而loadclass是没有进行到这里的,所以只能用class.forname()的方式。

独特的new加载时机

网上查阅资料,因为我是合法的公民,并没有饭前over the wall,所以得到的答案千篇一律

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。
而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载 java
API的那个加载器。

其中的“但是使用newInstance()方法的时候,就必须保证:1、这个类已经加载;2、这个类已经连接了。”(当然上面说是必须保证已经初始化了,这个先不纠结)这个不用那个说因为class.forname()所以情有可原,可是 “ 我们使用关键字new创建一个类的时候,这个类可以没有被加载。” 我始终想不到答案,终于通过博文:https://blog.csdn.net/justloveyou_/article/details/72466416
https://blog.csdn.net/justloveyou_/article/details/72466105
尤其是第二篇中的例子:

public class StaticTest {    public static void main(String[] args) {        staticFunction();    }    static StaticTest st = new StaticTest();    static {   //静态代码块        System.out.println("1");    }    {       // 实例代码块        System.out.println("2");    }    StaticTest() {    // 实例构造器        System.out.println("3");        System.out.println("a=" + a + ",b=" + b);    }    public static void staticFunction() {   // 静态方法        System.out.println("4");    }    int a = 110;    // 实例变量    static int b = 112;     // 静态变量}/* Output:         2        3        a=110,b=0        1        4

请仔细阅读笔者中的这句话:

此时,就碰到了笔者上面的疑惑,即“在类都没有初始化完毕之前,能直接进行实例化相应的对象吗?”。事实上,从Java角度看,我们知道一个类初始化的基本常识,那就是:在同一个类加载器下,一个类型只会被初始化一次。所以,一旦开始初始化一个类型,无论是否完成,后续都不会再重新触发该类型的初始化阶段了(只考虑在同一个类加载器下的情形)。因此,在实例化上述程序中的st变量时,实际上是把实例初始化嵌入到了静态初始化流程中,并且在上面的程序中,嵌入到了静态初始化的起始位置。这就导致了实例初始化完全发生在静态初始化之前,当然,这也是导致a为110b为0的原因。

关键信息: 在同一个类加载器下,一个类型只会被初始化一次。所以,一旦开始初始化一个类型,无论是否完成,后续都不会再重新触发该类型的初始化阶段了(只考虑在同一个类加载器下的情形)。

注意上面的代码,将static StaticTest st = new StaticTest();即new的操作放到了类的加载过程中的初始化阶段,这也就导致了 上面所说的 使用new的时候,类可以没有被加载完,因为还停留在初始化阶段就已经执行了new的操作了!!!!!!!!!!!!!!

类加载器不同

new和newinstance使用的类加载器是相同的,都是当前类加载器。(即:this.getClass.getClassLoader)。loadclass由用户指定类加载器。如果需要在当前类路径以外寻找类,则只能采用第loadclass种方式。第3种方式加载的类与当前类分属不同的命名空间。另外,new是静态加载,newinstance、loadclass是动态加载

效率不同

网上都是对” Class.forName(“”).newinstance( “这样的字眼一带而过,当然我也没有找到更好的答案。
当然还是有的:
https://blog.csdn.net/xqlovetyj/article/details/82798864
还有这个(参考价值不大):
https://blog.csdn.net/lzljs3620320/article/details/51111112
但是看得我似懂非懂,估计看完隔天就忘了,但是确实是有效率问题的,newinstance大概比new要低一个数量级。

调用的方法不同

newinstance:只能调用无参构造。
new:能调用任何public构造。

newinstance真正的用途

参考:https://www.cnblogs.com/liuyanmin/p/5146557.html

    String className = readfromXMlConfig;//从xml 配置文件中获得字符串    class c = Class.forName(className);    factory = (ExampleInterface)c.newInstance();

上面代码已经不存在Example的类名称,它的优点是,无论Example类怎么变化,上述代码不变,甚至可以更换Example的兄弟类Example2 , Example3 , Example4……,只要他们继承ExampleInterface就可以。
总结: 动态加载

---------------------
作者:as403045314
来源:CSDN
原文:https://blog.csdn.net/as403045314/article/details/101337322

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值