Android 反射機制的理解

之前在網(wǎng)上找有關(guān)反射機制的資料發(fā)現(xiàn)網(wǎng)上關(guān)于這塊的資料不多,而且不太容易懂,所以試著寫一篇我自己所理解的反射機制希望能多你有所幫助.


首先來看看用反射機制和用以前的方法新建對象實例有什么不同

第一步新建一個Person對象

用以前的方法是:

Person p = new Person();

在內(nèi)存中新建一個Person的實例,對象p對這塊內(nèi)存地址進行引用

用反射機制實現(xiàn) (有三種方法):

第一種:

Class<?> cls=Class.forName("com.fanshe.Person"); //forName(包名.類名)
Person p=(Person)cls.newInstance();

1.通過JVM查找并加載指定的類(上面的代碼指定加載了com.fanshe包中的Person類)
2.調(diào)用newInstance()方法讓加載完的類在內(nèi)存中創(chuàng)建對應的實例,并把實例賦值給p

第二種:

Person p = new Person();
Class<?> cls=p.getClass();
Person p2=(Person)cls.newInstance();

1.在內(nèi)存中新建一個Person的實例,對象p對這個內(nèi)存地址進行引用
2.對象p調(diào)用getClass()返回對象p所對應的Class對象
3.調(diào)用newInstance()方法讓Class對象在內(nèi)存中創(chuàng)建對應的實例,并且讓p2引用實例的內(nèi)存地址

第三種:

Class<?> cls=Person.Class();
Person p=(Person)cls.newInstance();

1.獲取指定類型的Class對象,這里是Person
2.調(diào)用newInstance()方法在讓Class對象在內(nèi)存中創(chuàng)建對應的實例,并且讓p引用實例的內(nèi)存地址

注意:
cls.newInstance()方法返回的是一個泛型T,我們要強轉(zhuǎn)成Person類
cls.newInstance()默認返回的是Person類的無參數(shù)構(gòu)造對象
被反射機制加載的類必須有無參數(shù)構(gòu)造方法,否者運行會拋出異常


先來看看反射的好處

可能有人會有疑問,明明直接new對象就好了,為什么非要用反射呢?代碼量不是反而增加了?

其實反射的初衷不是方便你去創(chuàng)建一個對象,而是讓你在寫代碼的時候可以更加靈活,降低耦合,提高代碼的自適應能力.

怎么樣降低耦合度,提高代碼的自適應能力?

通過接口實現(xiàn),但是接口如果需要用到new關(guān)鍵字,這時候耦合問題又會出現(xiàn)
舉個栗子:

public static void main(String[] args) {
    HeroFacrty facrty =new HeroFacrty();
    hero iroman= facrty.CreateHero("IronMan");
    iroman.attach();
}

public hero CreateHero(String name) {
    if ((name).equals("IronMan")) {
        return new IronMan();
    }
    if ((name).equals("Hulk")) {
        return new Hulk();
    }
    return null;
}

interface hero {
    public void attach();
}

class IronMan implements hero {

    @Override
    public void attach() {
        System.out.println("Laser Light");

    }
}

class Hulk implements hero {

    @Override
    public void attach() {
        System.out.println("fist");

    }
}

假設有1000個不同Hero需要創(chuàng)建,那你打算寫1000個 if語句來返回不同的Hero對象?

如果使用反射機制呢?

public static void main(String[] args) {
        HeroFacrty facrty = new HeroFacrty();
        Hero hero=facrty.CreateHero("test.IroMan");
        hero.attack();
    }

    public Hero CreateHero(String name) {
        try {
            Class<?> cls = Class.forName(name);
            Hero hero = (Hero) cls.newInstance();
            return hero;
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;

    }

}

class IroMan implements Hero {

    @Override
    public void attack() {
        System.out.println("Laser Light");

    }
}

class Hulk implements Hero {

    @Override
    public void attack() {
        System.out.println("Fist");

    }
}

interface Hero {
    public void attack();
}

利用反射機制進行解耦的原理就是利用反射機制"動態(tài)"的創(chuàng)建對象:向CreateHero()方法傳入Hero類的包名.類名 通過加載指定的類,然后再實例化對象.

對于反射機制舉個不太嚴謹?shù)睦踝?

當你電腦需要使用鼠標時,你向電腦USB接口插入鼠標,鼠標向電腦發(fā)送驅(qū)動請求,驅(qū)動的型號為NFTW-2196的驅(qū)動.這時候電腦在驅(qū)動集合中查找驅(qū)動,找到后運行驅(qū)動鼠標能用了,插入鍵盤同理.


說完了反射機制如何生成類對象,那生成了對象以后當然要開始調(diào)用類的方法了

在調(diào)用方法前先了解Class<?> cls=Class.forName("fanshe.Person");cls內(nèi)部有哪些方法供我們使用.

方法關(guān)鍵字 含義
getDeclareMethods() 獲取所有的方法
getReturnType() 獲取方法的返回值類型
getParameterTypes() 獲取方法的傳入?yún)?shù)類型
getDeclareMethod("方法名,參數(shù)類型.class,....") 獲得特定的方法
-
構(gòu)造方法關(guān)鍵字 含義
getDeclaredConstructors() 獲取所有的構(gòu)造方法
getDeclaredConstructors(參數(shù)類型.class,....) 獲取特定的構(gòu)造方法
-
成員變量 含義
getDeclaredFields 獲取所有成員變量
getDeclaredField(參數(shù)類型.class,....) 獲取特定的成員變量
-
父類和父接口 含義
getSuperclass() 獲取某類的父類
getInterfaces() 獲取某類實現(xiàn)的接口

以下面的Person來做講解,稍后我們會用反射實現(xiàn)下面的代碼:

public class fanshe03 {

    public static void main(String[] args) {
        Person person=new Person();
        person.setName("Lipt0n");
        System.out.print(person.getName);
    }
}
class Person {

    String name;
    
    public Person() {
    }

    public Person(String name) {
        super();
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    

很簡單步驟分為三步:

  1. 實例化一個Person類對象
  2. 調(diào)用Person.setName("name")設置名字
  3. 在控制臺打印Person.getName()的值
現(xiàn)在我們用反射機制來實現(xiàn)上面的代碼:
public static void main(String[] args) {

         try {
         Class<?> cls=Class.forName("test.Person");//加載Person類
         Object object=(Object) cls.newInstance();//實例化Person
         Method setname=cls.getDeclaredMethod("setName", String.class);//獲取setName()方法
         setname.invoke(object, "Lipt0n");//設置調(diào)用setName的對象和傳入setName的值
         Method getname=cls.getDeclaredMethod("getName");//獲取getName方法
         System.out.print(getname.invoke(object, null));//設置調(diào)用getName方法的對象.把值打印到控制臺
         
         } catch (Exception e) {
         e.printStackTrace();
         }
    }

Java程序可以加載一個運行時才得知名稱的class,獲悉其完整構(gòu)造,并生成其對象實體、或?qū)ζ涑蓡T變量賦值、或調(diào)用其方法。這種“看透class”的能力稱為反射.--(摘自網(wǎng)上的一段話,具體出處忘記了)


</br>

寫到這里反射機制的基本用法和好處都基本講完了.以上就是我對反射機制的理解,希望寫出來的東西能對你有所幫助.如果你發(fā)現(xiàn)文章有錯誤的地方希望可以指出,以免誤導他人 : )
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 學習Android的同學注意了?。?!學習過程中遇到什么問題或者想獲取學習資源的話,歡迎加入Android學習交流群...
    kingZXY2009閱讀 353評論 0 0
  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,042評論 0 9
  • 文 丨楊小邪 公眾號丨瀾潤她世界(lrwomen) 小洛跟我講了件趣事,她派對上認識一位男士。眉目清秀,氣質(zhì)...
    瀾潤她世界閱讀 1,783評論 0 0
  • 要離開了,心有執(zhí)念。 很多人對說我安穩(wěn),實際上我心最跳。 很多人說我淡然,安詳,無欲,只是我自己知道自己的能力壓抑...
    靜靜的等待著閱讀 393評論 0 0

友情鏈接更多精彩內(nèi)容