反射的好處
我們在第一次接觸反射的時候,總會有個很大的疑問,反射看起來好麻煩啊,各種get.get,他究竟有什么好處,能用來做什么呢?
我們先來看一下《編程思想》這本書中是怎么說的.
RTTI和反射之間真正的區別只在於,對RTTI來說,編譯器在在編譯時打開和檢查.class文件.(換句話說,我們可以用"普通"方式調用對象的所有方法).對於反射機制來說,.class文件在編譯時是不可獲取的,所以在運行時打開和檢查.class文件。 --《編程思想》
這段話看起來很叼的樣子,有點雲里霧里的,首先RTTI的意思就是以普通的方式來創建對象,調用方法,就是我們常用的new關鍵字。這段話的意思簡化版就是:編譯器將.java文件編譯成.class文件之后,普通方式創建的對象就不能再變了,我只能選擇是運行還是不運行這個.class文件。是不是感覺很僵硬,假如現在我有個寫好的程序已經放在了服務器上,每天供人家來訪問,這時候Mysql數據庫宕掉了,改用Oracle,這時候該怎么怎么辦呢?假如沒有反射的話,我們是不是得修改代碼,將Mysql驅動改為Oracle驅動,重新編譯運行,再放到服務器上。是不是很麻煩,還影響用戶的訪問。
假如我們使用反射Class.forName()來加載驅動,只需要修改配置文件就可以動態加載這個類,Class.forName()生成的結果在編譯時是不可知的,只有在運行的時候才能加載這個類,換句話說,此時我們是不需要將程序停下來,只需要修改配置文件里面的信息就可以了。這樣當有用戶在瀏覽器訪問這個網站時,都不會感覺到服務器程序程序發生了變化。
所以在《Mybatis技術原理與實戰》是這么說反射的好處的。
配置性大大提高,如同Spring IOC容器,給很多配置設置參數,使得java應用程序能夠順利跑起來,大大提高了Java的靈活性和可配置性,降低模塊間的耦合。--《Mybatis技術原理與實戰》
相應的實例
Eclipse的代碼自動補全就是利用了反射原理動態的加載要展示的方法,因為反射會影響性能,所以開了自動補全剛開始的時候會卡一下,主要還是我電腦性能不行。
反射的進階
在JDK動態代理中可以利用反射直接獲取到接口的方法來執行,從而可以將代理類要處理的代碼抽象出來形成統一的接口。
Java的反射中Class.forName和ClassLoader的區別
ClassLoader:
ClassLoader就是遵循雙親委派模型最終調用啟動類加載器的類加載器,實現的功能是“通過一個類的全限定名來獲取描述此類的二進制字節流”,獲取到二進制流后放到JVM中。
例如ClassLoader.getSystemClassLoader().loadClass("com.test.mytest.ClassForName");是不會初始化類的。
Class.forName():
Class.forName()方法實際上也是調用的CLassLoader來實現的。
Class.forName(String name, boolean initialize,ClassLoader loader)方法來手動選擇在加載類的時候是否要對類進行初始化。
應用場景:
1. 在我們熟悉的Spring框架中的IOC的實現就是使用的ClassLoader。
2. 使用JDBC時通常是使用Class.forName()方法來加載數據庫連接驅動。這是因為在JDBC規范中明確要求Driver(數據庫驅動)類必須向DriverManager注冊自己
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!");
}
}
public Driver() throws SQLException {
// Required for Class.forName().newInstance()
}
}
Class.forName()會初始化類,所以自動加載static代碼段,從而注冊自己。
