`

Aaron Johnson对Class.forName()的解释_翻译

阅读更多

A reader asked a question via a comment a couple months ago that I didn't really have an answer for (and had always kind of wondered the same thing). In the original post (which showed how to use JDBC with ColdFusion), I used the following snippet of code:
几个月之前,一个读者通过一篇评论向我提了一个问题,我一直没有真正给出答案(我一直在考虑一件事情)。我在原来的职位(我负责展示如何在ColdFusion上使用JDBC)时,我曾使用下面的代码片断:


Class.forName("jdbc.DriverXYZ");
Connection con = DriverManager.getConnection(url,
"myLogin", "myPassword");

and the reader wanted to know what the
Class.forName(..) method did. The most common answer you'll hear is that it loads the database driver, which, while technically true, is shallow. Where does it get loaded? How does it happen? And why?

那位读者想知道Class.forName(..) 方法到底做了些什么。通常你所听到的大多数回答都是它是用来加载数据库驱动的,虽然这个答案在技术上来说是正确的,但是太浅显了。到底是在哪里加载的?是怎么工作的?还有为什么要这样用?

To answer the question I started with the JavaDoc for the Class.forName() method. According to the documentation, the method:
... attempts to locate, load, and link the class or interface.I wasn't perfectly clear on what "locate, load, and link" meant, so I did a little digging through the
Java Language Specification. According to chapter 12 of the JLS: Loading refers to the process of finding the binary form of a class or interface type with a particular name, perhaps by computing it on the fly, but more typically by retrieving a binary representation previously computed from source code by a compiler, and constructing, from that binary form, a Class object to represent the class or interface.Next, again according to the JLS, it must be transformed from it's binary representation to something the Java virtual machine can use, this process is called linking. Finally, the class is initialized, which is the process that executes the static initializer and the initializers for static fields declared in the class.

要回答这个问题,我从Java文档中关于Class.forName()方法说明开始。根据文档的说明:…试图定位,加载,连接类或者接口。我不是很清楚到底“定位,加载和连接”是什么意思,因此我小小的研究了一下《Java 语言说明书》。根据其第12章关于JLS的说明:加载是指-根据指定的类或者接口的名字,找到其实际二进制文件的处理过程,或许是很匆忙的处理,但更典型的是指检索之前被编译器编译过的二进制文件,并且构造,二进制文件就是.class文件,它可能是类或接口。接着,还是依据JLS,二进制文件将被转化为Java虚拟机可以使用的东西,这个操作称为“连接”。最后类被初始化,如执行其静态初始化程序与初始化类中声明的静态变量。


So then back to the original problem, when Class.forName() is called with an argument like this:
所以我们现在回到最开始的问题,当Class.forName()被调用时,会有参数传入就像这样:

Class.forName("org.gjt.mm.mysql.Driver");

the classloader attempts to load and link the
Driver class in the "org.gjt.mm.mysql" package and if successful, the static initializer is run. The MySQL Driver (download the source code) static initializer looks like this:
类加载器尝试去加载和连接"org.gjt.mm.mysql"包里的Driver类,如果成功了,静态初始化程序将被运行,

MySQL Driver类(在这里下载源代码)静态初始化程序是这样的:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}

So it calls a static method in the
java.sql.DriverManager class which apparently registers a copy of itself when it loads.

从上面的代码中可以看到,它调用了java.sql.DriverManager的静态方法,很显然在它被加载的时候,它注册了一个自己的实例。


So now I understand the where and the how, what about why? To understand the why you have to look at the next line in the initial code example:
因此到目前为止我明白了在哪里加载与如何加载的,但是为什么非要这么做呢?想要了解为什么,你需要看下面的初始化代码样例:


Connection con = DriverManager.getConnection(url,
"myLogin", "myPassword");

The
DriverManager class (view DriverManager source here) returns a database connection given a JDBC URL string, a username and a password. In order to create that connection, the DriverManager class has to know which database driver you want to use. It does that by iterating over the array (internally a Vector) of drivers that have registered with it (ie: the registerDriver(Driver driver) method illustrated above) and calls the acceptsURL(url) method on each driver in the array, effectively asking the driver to tell it whether or not it can handle the JDBC URL.
So there you have it. Class.forName explained.

DriverManager类在给予它一个JDBC URL字符串,一个用户名与密码后,它会返回一个数据库的连接对象,DriverManager类需要知道你要使用哪个数据库驱动程序。要做到这一点,它要遍历一个驱动数组(内部由一个Vector实现),那些驱动就是之前注册过的(例如:上文中的registerDriver(Driver driver)方法)并且逐个调用数组中驱动类的acceptsURL(url)方法,实际上是让驱动程序反馈其是否可以处理这个 JDBC URL连接字符串。直到现在你该明白Class.forName的作用了吧。^_^

 

分享到:
评论

相关推荐

    Prism7.1.0.431_WPF_官方中文文档

    Prism是Microsoft Patterns & Practices团队开发的一个开源框架,主要用于构建模块化、可维护...虽然需要对翻译的准确性有所容忍,但借助Prism的丰富功能和良好设计原则,开发者能够创建出高效、可扩展的WPF应用程序。

    sort-by-name.rar_site:www.pudn.com_sortbyname

    在编程领域,排序是至关重要的一个操作...总之,"sort-by-name.rar"文件中的算法可能涉及了如何利用C++的标准库函数和自定义比较函数,按照字典顺序对姓名列表进行排序,这在数据处理和分析中是非常常见且实用的技能。

    opencv4.1.1已编译opencv_contrib.zip

    《OpenCV4.1.1在VS2019下的编译与应用详解》 OpenCV,全称Open Source Computer Vision Library,是一个开源的计算机视觉和机器学习软件库,广泛应用于图像处理、计算机视觉以及相关的机器学习领域。...

    web.py中文教程_脚本之家.docx

    该框架由美国作家、Reddit联合创始人、RSS规格合作创造者、著名计算机黑客Aaron Swartz开发。web.py目前已被很多家大型网站所使用。 web.py简单易学,只要有Python基础,掌握web.py就非常容易。

    apache server 实用全书.ISO

    ______________________________________________ Apache Server Unleashed ______________________________________________ This CD-ROM contains most of the programs the author ... Aaron Price Dan Scherf

    android permission常用权限大全.doc

    以下是对Android Permission大全中列出的一些常见权限的详细解释: 1. **ACCESS_CHECKIN_PROPERTIES**:这个权限允许应用读写checkin数据库中的"properties"表,这些数据可能被用来修改上传到服务器的信息。 2. **...

    FGL内置函数大全

    这些函数主要用于对数据进行统计分析,例如计算一组数值的总和、平均值、最大值或最小值。 #### 日期时间处理函数 1. **YEAR**(日期): 获取日期中的年份。 2. **MONTH**(日期): 获取日期中的月份。 3. **DAY**...

    matlab代码中fnames-erclustering:聚簇

    使用Erdős-Rényi聚类对电影进行端到端面部检测和演员分组 此代码计算N个不同的人脸图像之间的Rank-1 Count相似度得分。 编译中 g++ -o run.bin main.cpp Rank1Count.h Rank1Count.cpp 运行测试 默认情况下,此演示...

    chinese_L-12_H-768_A-12.rar

    这是一个已经训练好的中文bert模型,参数都是可以用的参数,可以直接拿来用。这个是轻量版的,不过要注意这个是基于Tensorflow的,不过据说有可以将其转化为pytorch版本的脚本,可以自己搜一下。

    binjascripts:二进制忍者实用程序脚本集

    受到Aaron Portnoy和arizvisa关于的工作的启发。 特征 缩短了API,可加快Binja终端的入侵速度。 f - current_function llil - current_function.low_level_il llilssa - current_function.low_level_il.ssa_form ...

    CrateDB单节点部署,集群部署,配置文件详解,问题解决及优化

    在安装CrateDB之前,需要对系统进行一定的配置以确保CrateDB能够顺利运行。这包括了对文件描述符数量的限制以及虚拟内存映射的数量的调整: - **文件描述符限制**:编辑`/etc/security/limits.conf`文件,设置文件...

    GRAT2:我们出于学习目的开发了GRAT2命令与控制(C2)项目

    GRAT2 C2 (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) (c).-.(c) / ._. \ / ._. \ / ._.... (_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._)(_.-/'-'\-._) || G || || R || || A || || T ||

    pybedtools:适用于Aaron Quinlan的BEDTools(生物信息学工具)的Python包装器以及更多内容

    概述 广泛用于基因组间隔操纵或“基因组代数”。 pybedtools包装并扩展了BEDTools,并提供了Python内部的功能级操作。 请参阅完整在线文档,包括安装说明。 为什么要使用pybedtools? 这是获取距基因间SNP小于5 ...

    status

    GitHub仪表板 2021-03-17 12:23:53 UTC # add WIP controljobs : render : name : Prepare System runs-on : macOS-latest if : " !contains(github.event.head_commit.message, 'WIP') " usethis :: use_github_...

    blockinhole:一个简单的儿童游戏,用EaselJS编写

    堵Kong这是一个简单的儿童游戏,由使用构建。项目结构使用生成样式表 stylesheets/|- home.scss ________________________________ # Tying it all together||- modules/| |- toy.scss ____________________________...

    WordPress Bible - Aaron Brazell-675.pdf

    WordPress Bible - Aaron Brazell-675

    bmo:bugzilla.mozilla.org源-在此处报告问题:https:bugzilla.mozilla.orgenter_bug.cgi?product = bugzilla.mozilla.org

    2. **Perl**:Perl是一种高级、通用的解释型编程语言,尤其擅长文本处理。在Web开发领域,Perl常常用于构建CGI(Common Gateway Interface)程序,如Bugzilla,用于接收和处理来自Web服务器的请求。 3. **源代码...

    madlib:PAM后门

    马德利卜 特征: ... 自动更新所有移动/替换文件的 DPKG MD5 哈希 时间踩踏所有移动/替换的文件 更新 SE Linux 配置以允许更改文件 用 /bin/bash 替换 /bin/false 和 /bin/nologin... .___.__ ._____. _____ _____ __|

    河南省许昌市许昌县第三高级2019 2020学年高一英语月考试题.doc

    【中学试卷】的相关知识点主要涉及英语语法、词汇和表达习惯,以下是对题目中出现的知识点进行的详细解析: 1. **虚拟语气** - 第一题考察的是条件状语从句中的虚拟语气。句子"If you come this afternoon, we ____...

Global site tag (gtag.js) - Google Analytics