JAVA 反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。java
簡單來講就是反射就是將 Java 類中的各類成分映射成一個個的 Java 對象。mysql
假若有兩個程序員,一個程序員在寫程序的時須要使用第二個程序員所寫的類,但第二個程序員並沒完成他所寫的類。那麼第一個程序員的代碼是不能經過編譯的。此時,利用 Java 反射的機制,就可讓第一個程序員在沒有獲得第二個程序員所寫的類的時候,來完成自身代碼的編譯。程序員
Java 的反射機制它知道類的基本結構,這種對 Java 類結構探知的能力,咱們稱爲Java 類的「自審」。例如 一個類有:成員變量、方法、構造方法、包等等信息,利用反射技術能夠對一個類進行解剖,把個個組成部分映射成一個個對象。在 Java 中萬物皆是對象,反射也是面向對象思想的一種體現。spring
首先 咱們來建立一個 Robot 類。sql
public class Robot {
private String name;
public void sayHi(String helloSentence) {
System.out.println(helloSentence + " " + name);
}
private String throwHello(String tag) {
return "Hello " + tag;
}
}
複製代碼
如代碼所示,咱們定義了一個私有的成員變量以及兩個方法。bash
接下來咱們就經過反射來獲取它。ui
public class ReflectSample {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {
Class rc = Class.forName("com.interview.javabasic.reflect.Robot");
Robot r = (Robot) rc.newInstance();
System.out.println("Class name is " + rc.getName());
Method getHello = rc.getDeclaredMethod("throwHello", String.class);
getHello.setAccessible(true);
Object str = getHello.invoke(r, "Bob");
System.out.println("getHello result is " + str);
Method sayHi = rc.getMethod("sayHi", String.class);
sayHi.invoke(r, "Welcome");
Field name = rc.getDeclaredField("name");
name.setAccessible(true);
name.set(r, "Alice");
sayHi.invoke(r, "Welcome");
}
}
複製代碼
首先咱們建立一個 Class對象 rc,而且經過 forName方法來給它賦值。這裏我先給你提一個小問題,loadClass 和 forName 的區別,你能夠先思考一下,答案會在文末給出。spa
接着咱們的例子,咱們經過 newInstance() 方法來創造一個實例,而且其強轉爲Robot對象。 緊接着咱們輸出 rc 的 name,rc 是經過咱們傳遞的路徑獲得的,因此 name 天然是咱們但願建立的 Robot 類。code
咱們經過 rc.getDeclaredMethod()方法獲得了一個method對象,方法的參數對應着咱們但願獲得方法的名稱。因爲該方法是私有方法,因此咱們 將 setAccessible() 設爲true,表示反射在應用的時候,不會去進行權限檢查。對象
因爲 throwHello方法須要參數,咱們就傳入了Bob,最後輸出的結果是 getHello result is Hello Bob
經過上述的代碼,咱們獲得了 Robot對象以及它的方法,算是初步對反射有了必定的應用(後半部分的代碼屬於換湯不換藥,就再也不贅述)。
它們的區別就是 Class.forName獲得的class是已經完成初始化完成的,Classloder.loadClass獲得的class是尚未連接的。
簡單來講就是 forName方法會執行類中靜態代碼塊中的內容,而 loadClass不會執行,咱們舉一個簡單的例子。
以 Class.forName("com.mysql.jdbc.Driver") 爲例; Driver 類中有須要執行靜態代碼塊(new Driver) 因此要用forname 不能loadclass。而springIoc 在讀取bean的配置的時候 採起的是lazyloading(延時加載)的策略,使用 classloader 不須要執行靜態代碼塊能夠加快初始化速度,把相關加載留到真正執行代碼的時候再操做。因此說這兩種方法各有優劣,須要根據實際狀況而定。
在本文中咱們講到了 Java 反射的相關內容,但願你看完本文後有所收穫。