談一談Java中的反射機制

什麼是反射?

JAVA 反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。java

簡單來講就是反射就是將 Java 類中的各類成分映射成一個個的 Java 對象。mysql

在咱們瞭解了反射的基本概念以後,天然而然的咱們就提出瞭如下問題,反射有什麼用?

假若有兩個程序員,一個程序員在寫程序的時須要使用第二個程序員所寫的類,但第二個程序員並沒完成他所寫的類。那麼第一個程序員的代碼是不能經過編譯的。此時,利用 Java 反射的機制,就可讓第一個程序員在沒有獲得第二個程序員所寫的類的時候,來完成自身代碼的編譯。程序員

Java 的反射機制它知道類的基本結構,這種對 Java 類結構探知的能力,咱們稱爲Java 類的「自審」。例如 一個類有:成員變量、方法、構造方法、包等等信息,利用反射技術能夠對一個類進行解剖,把個個組成部分映射成一個個對象。在 Java 中萬物皆是對象,反射也是面向對象思想的一種體現。spring

說了這麼多,感受 好像仍是雲裏霧裏。那接下來就開始 show code。

首先 咱們來建立一個 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對象以及它的方法,算是初步對反射有了必定的應用(後半部分的代碼屬於換湯不換藥,就再也不贅述)。

最後,咱們來解答文中的問題 loadClass和forName有什麼區別?

它們的區別就是 Class.forName獲得的class是已經完成初始化完成的,Classloder.loadClass獲得的class是尚未連接的。

簡單來講就是 forName方法會執行類中靜態代碼塊中的內容,而 loadClass不會執行,咱們舉一個簡單的例子。

以 Class.forName("com.mysql.jdbc.Driver") 爲例; Driver 類中有須要執行靜態代碼塊(new Driver) 因此要用forname 不能loadclass。而springIoc 在讀取bean的配置的時候 採起的是lazyloading(延時加載)的策略,使用 classloader 不須要執行靜態代碼塊能夠加快初始化速度,把相關加載留到真正執行代碼的時候再操做。因此說這兩種方法各有優劣,須要根據實際狀況而定。

在本文中咱們講到了 Java 反射的相關內容,但願你看完本文後有所收穫。

相關文章
相關標籤/搜索