Class.forName解析以及使用
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
這個(gè)類(lèi)在剛學(xué)習(xí)Java連接數(shù)據(jù)庫(kù)的時(shí)候見(jiàn)到這個(gè)這種寫(xiě)法,并且工作這么多年,也許是接觸的東西比較少,這種用法也就只有在自己手寫(xiě)數(shù)據(jù)庫(kù)連接代碼的時(shí)候見(jiàn)過(guò),在其他的時(shí)候還真是沒(méi)見(jiàn)過(guò)。
在Class類(lèi)中,對(duì)此方法有如下聲明
方法重載了三次。
查看第一個(gè)forName方法的聲明為:
@CallerSensitive public static Class<?> forName(String className)throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller); }首先在這個(gè)方法中,使用到了Reflection.getCallerClass(),返回是調(diào)用者對(duì)象
針對(duì)getCallerClass這個(gè)方法,這個(gè)方法是native的,聲明如下:
@CallerSensitive public static native Class getCallerClass();由于是native方法,就暫時(shí)不跟進(jìn)去了,這個(gè)方法的意思返回調(diào)用者 (class對(duì)象),也就是說(shuō)是誰(shuí)調(diào)用調(diào)用了我這個(gè)類(lèi)的方法。如下示例:
public class ReflectionCaller {public static void main(String[] args) {InnerClass i = new InnerClass();i.innerMethod();} }class InnerClass {public void innerMethod() {System.out.println(Reflection.getCallerClass());} }運(yùn)行以上代碼,輸出的結(jié)果是:
也就是ReflectionCaller這個(gè)類(lèi)對(duì)象。這個(gè)方法還是比較有趣的,如果在以后我們自己寫(xiě)代碼的時(shí)候,想知道誰(shuí)在調(diào)用我這些的這些方法,就可以跟蹤出來(lái)了。
獲取調(diào)用者信息以后,會(huì)調(diào)用Class.forname0方法,進(jìn)行加載和初始化類(lèi)。看到forname0這個(gè)方法又是一個(gè)native方法。
private static native Class<?> forName0(String name, boolean initialize,ClassLoader loader,Class<?> caller)throws ClassNotFoundException;這個(gè)方法的作用是根據(jù)name加載傳遞過(guò)來(lái)的類(lèi),并且根據(jù)initialize來(lái)決定是否要進(jìn)行初始化,所謂初始化指的是加載里面的靜態(tài)塊之類(lèi)的。加載的時(shí)候采用caller相同的類(lèi)加載器記性加載。
?
從中可以看出Class.forName和Classloader.lodeclass的區(qū)別是什么,Class.forName可以加載類(lèi)并且控制是否要對(duì)類(lèi)進(jìn)行初始化,而ClassLoader.loadClass只對(duì)類(lèi)進(jìn)行加載,不進(jìn)行初始化。
?
知道了Class.forName 的作用,那接下來(lái)就看一下針對(duì)連接mysql的具體問(wèn)題。
根據(jù)第一節(jié),可以看到連接字符串為:
Class.forName("com.mysql.jdbc.Driver");
也就是說(shuō)會(huì)加載com.mysql.jdbc.Driver這個(gè)類(lèi),并且進(jìn)行初始化。找到mysql-connector-java.jar的源碼,這個(gè)類(lèi)非常簡(jiǎn)單。
public class Driver extends NonRegisteringDriver implements java.sql.Driver {//// Register ourselves with the DriverManager//static {try {java.sql.DriverManager.registerDriver(new Driver());} catch (SQLException E) {throw new RuntimeException("Can't register driver!");}}/*** Construct a new driver and register it with DriverManager* * @throws SQLException* if a database error occurs.*/public Driver() throws SQLException {// Required for Class.forName().newInstance()} }這個(gè)類(lèi)中 就一個(gè)靜態(tài)塊和一個(gè)無(wú)參的構(gòu)造函數(shù),通過(guò)靜態(tài)塊的內(nèi)容可以看出,實(shí)例了的一個(gè)Driver,然后注冊(cè)到DriverManager,DriverManager把這個(gè)Driver存儲(chǔ)到了一個(gè)CopyOnWriteArrayList中。
同時(shí)Driver還繼承了AbandonedConnectionCleanupThread這個(gè)類(lèi),這個(gè)類(lèi)繼承Thread,啟動(dòng)一個(gè)守護(hù)線程,然后清理廢棄的類(lèi)對(duì)象。
以上就是我們?cè)谶B接mysql時(shí),Class.forName的功能。但是需要注意的是
Java 的SQL框架允許多個(gè)數(shù)據(jù)庫(kù)的Driver,每一個(gè)Driver都要實(shí)現(xiàn)java.sql.Driver接口,針對(duì)給出來(lái)的連接數(shù)據(jù)庫(kù)的請(qǐng)求,DriverManager嘗試去load盡可能多的它找到的drivers,然后根據(jù)這些driver嘗試使用給出來(lái)的數(shù)據(jù)庫(kù)連接字符串去嘗試連接數(shù)據(jù)庫(kù)。
在mysql的NonRegisteringDriver中強(qiáng)烈建議,每個(gè)驅(qū)動(dòng)程序類(lèi)應(yīng)該盡可能的小和獨(dú)立,這樣在加載和查詢驅(qū)動(dòng)類(lèi)的時(shí)候,才不會(huì)引入大量的支持代碼。
?
轉(zhuǎn)載于:https://my.oschina.net/u/2457218/blog/818082
總結(jié)
以上是生活随笔為你收集整理的Class.forName解析以及使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 现学现卖微信小程序开发(二)
- 下一篇: linux安装部署apache+subv