简单总结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 DriverManager
static {
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就可以。
总结: 动态加载
简单总结Class.forName("").newinstance()和new()以及classLoader.loadClass("")的区别的更多相关文章
- Class.forName() 与 ClassLoader.loadClass()的区别
看到一个面试题,说说Class.forName() 与 ClassLoader.loadClass()的区别,特意记录一下,方便后续查阅. 在我们写java代码时,通常用这两种方式来动 ...
- Class.forName和ClassLoader.loadClass的区别
Class的装载分了三个阶段,loading,linking和initializing,分别定义在The Java Language Specification的12.2,12.3和12.4. Cla ...
- 反射中Class.forName()和ClassLoader.loadClass()的区别
一 Java类装载过程 装载:通过累的全限定名获取二进制字节流,将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lang.class对象: 链接:执行下面的校验.准备和解析步骤,其 ...
- 015 反射中的 Class.forName() 与 ClassLoader.loadClass() 的区别
作者:nnngu GitHub:https://github.com/nnngu 博客园:http://www.cnblogs.com/nnngu 简书:https://www.jianshu.com ...
- 反射中的 Class.forName() 与 ClassLoader.loadClass() 的区别
在Java中,类加载器把一个类加载进Java虚拟机中,要经过三个步骤来完成:加载.链接和初始化,其中链接又可以分成验证.准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下 ...
- Class.forName和ClassLoader.loadClass的区别(转载)
Class的装载分了三个阶段,loading,linking和initializing,分别定义在The Java Language Specification的12.2,12.3和12.4.Clas ...
- Class.forName(),Class.forName().newInstance() ,New ,类名.class,,class.forName(),,getClass()
在Java开发特别是数据库开发中,经常会用到Class.forName( )这个方法.通过查询Java Documentation我们会发现使用Class.forName( )静态方法的目的是为 ...
- Class.forName()、Class.forName().newInstance() 、New 三者区别!
终于明白为什么加载数据库驱动只用Class.forName()了!!困扰了我2个小时!!希望我写的这个东西对各位有所帮助. 在Java开发特别是数据库开发中,经常会用到Class.forNa ...
- java中Class.forName("xxx")和ClassLoader().loadClass("xxx")的区别
一.首先,查看Class类中的forName方法,可以发现有如下三个方法,但是我们通常用的是只有一个参数的方法. 简单介绍一下这三个方法: 第一个方法Class.forName("xxx&q ...
随机推荐
- leetcood学习笔记-66-加一
题目描述: 第一次提交: class Solution: def plusOne(self, digits): digits[-1]=digits[-1]+1 for i in range(len(d ...
- 【安装】Mac rabbitMQ
安装 brew install rabbitmq 目录 cd /usr/local/Cellar/rabbitmq/3.7.4/sbin 插件 sudo ./rabbitmq-plugins ena ...
- alert样式优化
//alert样式优化 function alert(msg, mode) { //mode为空,即只有一个确认按钮,mode为1时有确认和取消两个按钮 msg = msg || ''; mode = ...
- 基于bootstrap的时间选择插件daterangepicker以及汉化方法
双日历时间段选择插件 — daterangepicker是bootstrap框架后期的一个时间控件: 可以设定多个时间段选项:也可以自定义时间段:由用户自己选择起始时间和终止时间:时间段的最大跨度可以 ...
- BZOJ 1415: [Noi2005]聪聪和可可(记忆化搜索+期望)
传送门 解题思路 还是比较简答的一道题.首先\(bfs\)把每个点到其他点的最短路求出来,然后再记忆化搜索.记搜的时候猫的走法是确定的,搜一下老鼠走法就行了. 代码 #include<iostr ...
- NX二次开发-隐藏对象UF_OBJ_set_blank_status
NX9+VS2012 #include <uf.h> #include <uf_curve.h> #include <uf_obj.h> UF_initialize ...
- idea和eclipse快捷键对比(转)
分类 功能点 Eclipse快捷键 IDEA快捷键 搜索 搜索文本 Ctrl + F Ctrl + F Ctrl + R 查找替换 Alt + P/A 逐个/全部替换 Alt + F3 查找当前选中词 ...
- (干货)java中如何根据一个时间获取属于本年那一周,本周的开始时间以及最后一天时间。并且设置起始时间为周6.结束时间为周5
本人亲测,有用,适用性比较强,直接上代码说话. package com.helloBike.data; import java.text.ParseException; import java.tex ...
- ## jvm知识点零碎整理
1.初始化VM options配置 idea安装目录\bin\idea.exe.vmoptions 和 idea64.exe.vmoptions可以看到初始配置: -Xms128m (设置初始化堆内 ...
- idea右键无run选项
选中java 文件所在的package右键选中Mark Directory as---Sources Root