JVM中class对象加载方式
1 class对象详解
java
中把生成Class
对象和实例对象弄混了,更何况生成Class
对象和生成instance
都有多种方式。所以只有弄清其中的原理,才可以深入理解。首先要生成Class
对象,然后再生成Instance
。那Class
对象的生成方式有哪些呢,以及其中是如何秘密生成的呢?
Class
对象的生成方式如下:
Class.forName("类名字符串")
(注意:类名字符串必须是全称,包名+类名)类名.class
实例对象.getClass()
通过一段小程序,来观察一下Class
对象的生成的原理。
public class TestClass {
public static void main(String[] args) {
try {
//测试Class.forName()
Class testTypeForName=Class.forName("TestClassType");
System.out.println("testForName---"+testTypeForName);
//测试类名.class
Class testTypeClass=TestClassType.class;
System.out.println("testTypeClass---"+testTypeClass);
//测试Object.getClass()
TestClassType testGetClass= new TestClassType();
System.out.println("testGetClass---"+testGetClass.getClass());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class TestClassType{
//构造函数
public TestClassType(){
System.out.println("----构造函数---");
}
//静态的参数初始化
static{
System.out.println("---静态的参数初始化---");
}
//非静态的参数初始化
{
System.out.println("----非静态的参数初始化---");
}
}
测试的结果如下:
---静态的参数初始化---
testForName---class TestClassType
testTypeClass---class TestClassType
----非静态的参数初始化---
----构造函数---
testGetClass---class TestClassType
根据结果可以发现,三种生成的Class
对象一样的。并且三种生成Class
对象只打印一次静态的参数初始化
。
我们知道,静态的方法属性初始化,是在加载类的时候初始化。而非静态方法属性初始化,是new类
实例对象的时候加载。
因此,这段程序说明,三种方式生成Class对象
,其实只有一个Class
对象。在生成Class
对象的时候,首先判断内存中是否已经加载。
所以,生成Class
对象的过程其实是如此的:当我们编写一个新的java类
时,JVM
就会帮我们编译成class对象
,存放在同名的.class文件
中。在运行时,当需要生成这个类的对象,JVM
就会检查此类是否已经装载内存中。若是没有装载,则把.class文件
装入到内存中。若是装载,则根据class文件
生成实例对象。
2 Class.forName和ClassLoader.loadClass区别
2.1 jvm加载class步骤
Java
中class
是如何加载到JVM
中的:
class
加载到JVM
中有三个步骤:
装载
:(loading)找到class对应的字节码文件。连接
:(linking)将对应的字节码文件读入到JVM中。初始化
:(initializing)对class做相应的初始化动作。
2.2 两种方式的详细方法
Java
中两种加载class
到JVM
中的方式
-
Class.forName("className");
其实这种方法调运的是:Class.forName(className, true,ClassLoader.getCallerClassLoader())
方法
参数一:className
,需要加载的类的名称。
参数二:true,是否对class进行初始化(需要initialize)
参数三:classLoader,对应的类加载器 -
ClassLoader.laodClass("className");
其实这种方法调运的是:ClassLoader.loadClass(name, false)
方法
参数一:name,需要加载的类的名称
参数二:false,这个类加载以后是否需要去连接(不需要linking)
2.3 两种方式的区别
forName("")
得到的class
是已经初始化完成的
loadClass("")
得到的class
是还没有连接的
一般情况下,这两个方法效果一样,都能装载Class
。
但如果程序依赖于Class
是否被初始化,就必须用Class.forName(name)
了。
2.4 举例说明他们各自的使用方法
java
使用JDBC
连接数据库时候,我们首先需要加载数据库驱动。
Class.forName("com.mysql.jdbc.Driver");//通过这种方式将驱动注册到驱动管理器上
Connection conn = DriverManager.getConnection("url","userName","password");//通过驱动管理器获得相应的连接
查看com.mysql.jdbc.Driver源码:
public class Driver extends NonRegisteringDriver
implements java.sql.Driver
{
//注意,这里有一个static的代码块,这个代码块将会在class初始化的时候执行
static
{
try
{
//将这个驱动Driver注册到驱动管理器上
DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
}
Class.forName("com.mysql.jdbc.Driver")
方法以后,他会进行class
的初始化,执行static
代码块。
也就是说class
初始化以后,就会将驱动注册到DriverManageer
上,之后才能通过DriverManager
去获取相应的连接。
但是要是我们使用ClassLoader.loadClass(com.mysql.jdbc.Driver)
的话,不会link
,更也不会初始化class
。相应的就不会回将Driver
注册到DriverManager
上面,所以肯定不能通过DriverManager
获取相应的连接。
附录:JVM加载class文件原理
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了