Class.forname和ClassLoader.loadClass的源码分析
最近在研读《深入理解java虚拟机:JVM高继特性与最佳实践》第二版,
今天想起来很久前,写数据库连接,使用Class.forName,当时没有深究,所以便简单的看了下源码,顺便做了以下记录:
以下为简单的数据库连接代码:
String driver = "com.mysql.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/db_iot";
String username = "root";
String password = "123456";
Connection conn = null; try {
Class.forName(driver);
conn = (Connection) DriverManager.getConnection(url,username,password);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
//Class.forName源码:
public static Class<?> forName(String className)
throws ClassNotFoundException {
return forName0(className, true, //这里的true是是否初始化的标志,默认初始化
ClassLoader.getClassLoader(Reflection.getCallerClass()));
}
结合JVM的相关知识:类加载分为 加载,连接(验证,准备(类静态成员设置类型默认值),解析),初始化(类静态成员初始化,不包括构造器的初始化),使用,卸载
//以下为com.mysql.jdbc.Driver的静态代码块
static {
try {
DriverManager.registerDriver(new Driver());//registerDriver方法会将driver存入到类DriverManger的静态成员中去
} catch (SQLException var1) {
throw new RuntimeException("Can\'t register driver!");
}
}
因此,使用Class.forName(driver);的结果是:driver被初始化,driver被加载的DriverManager中,可被查看及使用。
但如果使用classLoader.loadClass("className");则是另一回事了,下面是classLoader.loadClass的源码:
public Class<?> loadClass(String name) throws ClassNotFoundException {
return loadClass(name, false);//看jdk的注解知道,参数false表示是否解析,即尚未初始化
}
所以,若使用classLoader.loadClass,则driver并不会被加载道DriverManager中。
以下为补充的类加载步骤:
@.加载:
1.通过“类全名”定位到类文件,并获取该类文件的二进制字节流;
2.class文件二进制字节流中的静态数据结构转换为方法区中动态的运行时数据结构;
3.在java堆中生成一个代表这个类的java.lang.Class对象,作为方法区中该类相关数据的访问入口。
@.连接-验证:
1.验证文件的各式是否正确:是否以魔数0xCAFEBABE开头,紧接着魔数是不是正确的主次版本号,主版本号最小45等等验证;
2.验证元数据是否合法:该类是否有父类(除了java.lang.object外都当有父类),是否继承了final修饰的类等等;
3.验证字节码是否安全:确保被验证类的方法在运行时不会做出危害虚拟机安全的行为,如保证跳转命令不会跳转到方法体意外的字节码命令上;
4.符号应用验证:对当前类意外的信息进行匹配性验证,如通过“类全限定名”是否可找到对应的类,方法是否可访问等等。
需要重视的是:Java类在编译期会被检查验证,但是我们无法保证,class文件不会被篡改,所以,虚拟机的验证期是非常重要的。
@连接-准备:
1.为类成员变量分配内存设置类型默认值(比如int,则设为0),这些内存都将在方法区中进行分配,但需要注意的是,若静态成员变量被final修饰,则此时会直接赋值,而不是取类型默认值。
@连接-解析:
1.,将类的符号应用(单纯的符号字面量,不涉及jvm内存)转为直接应用(直接定位到目标的内存地址);
@初始化:
1.“初始化”是类加载过程的最后一步,在此阶段,类的静态成员将会被赋值(静态方法将会被执行);
上面反复提到了方法区,以下为方法区的解释:
方法区:方法区是jvm运行时数据结构中的一部分,为所有线程共享(线程安全)。
方法区中主要存放类信息:
1.类的全限定名,直接超类的全限定名(如果是Object,则没有超类),类的类型(类还是接口),类的访问修饰符(public,abstract,final等),所有的直接接口的全限定名,常量池;
2.常量池中主要存放该类的 字段,方法信息,类变量信息,装在该类的装载器的引用,类型引用等。
------------------------------------------写到后来,就成了背诵了,卡壳了还要翻书---------------------------------------------------------
Class.forname和ClassLoader.loadClass的源码分析的更多相关文章
- 深度分析 Java 的 ClassLoader 机制(源码级别)
写在前面:Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中,JVM在加载类的时候,都是通过ClassLoa ...
- 深度分析Java的ClassLoader机制(源码级别)
写在前面:Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中,JVM在加载类的时候,都是通过ClassLoa ...
- 深度分析 Java 的 ClassLoader 机制(源码级别)(转)
写在前面:Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中,JVM在加载类的时候,都是通过ClassLoa ...
- 【JVM】深度分析Java的ClassLoader机制(源码级别)
原文:深度分析Java的ClassLoader机制(源码级别) 为了更好的理解类的加载机制,我们来深入研究一下ClassLoader和他的loadClass()方法. 源码分析 public abst ...
- 反射中Class.forName()和ClassLoader.loadClass()的区别
一 Java类装载过程 装载:通过累的全限定名获取二进制字节流,将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lang.class对象: 链接:执行下面的校验.准备和解析步骤,其 ...
- 【转】深度分析Java的ClassLoader机制(源码级别)
原链接 Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中, JVM在加载类的时候,都是通过ClassLoa ...
- 别翻了,这篇文章绝对让你深刻理解java类的加载以及ClassLoader源码分析【JVM篇二】
目录 1.什么是类的加载(类初始化) 2.类的生命周期 3.接口的加载过程 4.解开开篇的面试题 5.理解首次主动使用 6.类加载器 7.关于命名空间 8.JVM类加载机制 9.双亲委派模型 10.C ...
- Class.forName() 与 ClassLoader.loadClass()的区别
看到一个面试题,说说Class.forName() 与 ClassLoader.loadClass()的区别,特意记录一下,方便后续查阅. 在我们写java代码时,通常用这两种方式来动 ...
- 015 反射中的 Class.forName() 与 ClassLoader.loadClass() 的区别
作者:nnngu GitHub:https://github.com/nnngu 博客园:http://www.cnblogs.com/nnngu 简书:https://www.jianshu.com ...
随机推荐
- python小白——进阶之路——day3天-———容器类型数据+Number类型强制类型转换
-->Number 部分 int : 整型 浮点型 布尔类型 纯数字字符串 float: 整型 浮点型 布尔类型 纯数字字符串 complex: 整型 浮点型 布 ...
- [亲测]七步学会ASP.NET Core 2.0怎么发布/部署到Ubuntu Linux服务器并配置Nginx反向代理实现域名访问
前言 ASP.NET Core 2.0 怎么发布到Ubuntu服务器?又如何在服务器上配置使用ASP.NET Core网站绑定到指定的域名,让外网用户可以访问呢? 步骤 第1步:准备工作 一台Liun ...
- CF618F Double Knapsack 构造、抽屉原理
传送门 首先,选取子集的限制太宽了,子集似乎只能枚举,不是很好做.考虑加强限制条件:将"选取子集"的限制变为"选取子序列"的限制.在接下来的讨论中我们将会知道: ...
- spring boot到底帮我们做了那些事?
一.前言 上一篇介绍了注解,也是为这一篇做铺垫,传统的都是通过配置文件来启动spring,那spring boot到底是做了什么能让我们快速开发昵? 二.启动原理 看下程序启动的入口, ...
- JS 面向对象 ~ 继承的7种方式
前言: 继承 是 OO 语言中的一个最为人津津乐道的概念.许多 OO 语言都支持两种继承方式:接口继承 和 实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法.如前所述,由于函数没有签名,在 ...
- vue通过自定义指令 v-py 将名字转拼音
自定义指令 py: 1.新建 vue-py.js文件 import Vue from 'vue'; var chinesePointCode = { "a": [21834, 38 ...
- MongoDB系列:一、MongoDB和Redis区别
简介 MongoDB更类似Mysql,支持字段索引.游标操作,其优势在于查询功能比较强大,擅长查询JSON数据,能存储海量数据,但是不支持事务. Mysql在大数据量时效率显著下降,MongoDB更多 ...
- 解决多线程安全问题-无非两个方法synchronized和lock 具体原理(百度-美团)
还有其他的锁,如果想要了解,参考:JAVA锁机制-可重入锁,可中断锁,公平锁,读写锁,自旋锁, 用synchronized实现ReentrantLock 美团面试题参考:使用synchronized ...
- Node.js的事件处理机制
1. 为什么Node.js是单线程执行的 因为从JavaScript设计之初,JavaScript是用户与浏览器交互的,主要处理DOM: 这样决定了JavaScript是单线程执行,否则会出现问题:例 ...
- 基于vue现有项目的服务器端渲染SSR改造
前面的话 不论是官网教程,还是官方DEMO,都是从0开始的服务端渲染配置.对于现有项目的服务器端渲染SSR改造,特别是基于vue cli生成的项目,没有特别提及.本文就小火柴的前端小站这个前台项目进行 ...