<input id="0qass"><u id="0qass"></u></input>
  • <input id="0qass"><u id="0qass"></u></input>
  • <menu id="0qass"><u id="0qass"></u></menu>

    02、反射是什么?——《Android打怪升級之旅》

    Android打怪升級之旅 專欄收錄該內容
    2 篇文章 3 訂閱

    感謝大家和我一起,在Android世界打怪升級!

    反射在平時開發中使用幾率較小,但在各大框架中會頻繁使用(比如:老版本ButterKnife使用注解與反射初始化控件等,省略findViewById),如果有意向成為架構師,這塊知識的掌握必不可少。

    一、反射是什么

    平時開發中創建對象都是通過 new 關鍵字創建,通過該對象的實例,可以獲取該對象的可訪問成員變量或者調用可調用方法,此時我們明確知道使用的類是什么。

    那如果我們不知道要初始化的類是什么,就需要使用到JAVA為我們提供的反射API了。

    1.1 定義

    反射可以在程序的運行時

    • 構造任意一個類的對象
    • 了解任意一個對象所屬的類
    • 了解任意一個類的成員變量和方法
    • 調用任意一個對象的屬性和方法

    這種動態獲取程序信息以及動態調用對象的功能稱為反射機制。反射是JAVA被視為動態語言的關鍵。

    1.2 原理

    在運行時獲取到類,但是在運行時.java文件已經在編譯階段被編譯成了.class文件,所以反射的原理就是:運行時通過字節碼文件獲取到類的所有信息。

    1.3 優缺點

    優點:

    • 高自由度:可以無視訪問權限限制,被private修飾依然可以調用。

    缺點:

    • 性能差:反射特別耗時,慢于直接創建對象,所以在使用時要衡量帶來的收益是否大于性能的影響。
    • 安全性差:反射的高自由度直接導致類的封裝性被破壞。
      • 通過反射修改代碼時,由于是直接操作字節碼文件,如果對代碼不熟悉,及其容易因為修改而導致報錯。
      • 反射中有時會直接使用方法名,那在后期維護期間,如果方法名修改被修改,也會產生報錯。

    二、反射的使用

    Class類中方法特別多,我們只以舉例的方式寫幾個常用的例子,大家只需記住通過反射可以獲取一個類中所有的成員變量和方法(無視權限),你想要的全都有。

    2.1 運行時獲取類

    從1.2章節反射的原理可以曉得,反射的使用需要先在運行時獲取到類,運行時獲取到類一共有四種方法,根據情況選擇:

    1、運行時直接從類中獲取

    Class<Fruit> fruitClass1 = Fruit.class;
    

    2、運行時從對象中獲取對應的類

    Fruit fruit = new Fruit();
    Class fruitClass2 = fruit.getClass();
    

    3、運行時通過Class類的靜態方法獲取

    Class fruitClass3 = Class.forName("com.kproduce.androidstudy.test.Fruit");
    

    4、通過類加載器獲取

    Class fruitClass4 = getClassLoader().loadClass("com.kproduce.androidstudy.test.Fruit");
    

    最終這四種方式獲取的Class都是相同的。

    // 以下結果都是true
    System.out.println(fruitClass1 == fruitClass2);
    System.out.println(fruitClass2 == fruitClass3);
    System.out.println(fruitClass3 == fruitClass4);
    

    2.2 運行時創建對象

    通過在2.1中獲取的Class類來創建對象。

    // 在2.1中拿到的Class類
    Class<Fruit> fruitClass = Fruit.class;
    
    // 調用Class類中的方法創建對象
    Fruit fruit = fruitClass.newInstance();
    

    2.3 獲取構造方法

    一個類的構造方法因為參數不同可以很多,所以有API可以直接獲取所有構造方法 或者 根據參數不同獲取某個構造方法。

    // 帶有四個構造方法的類
    public class Fruit {
    
        public String name;
        private int type;
        
        public Fruit() {
        }
    
        public Fruit(String name) {
            this.name = name;
        }
    
        public Fruit(int type) {
            this.type = type;
        }
    
        public Fruit(String name, int type) {
            this.name = name;
            this.type = type;
        }
    }
    

    1、獲取所有構造方法:getConstructors()

    Constructor<Fruit>[] constructors = (Constructor<Fruit>[]) fruitClass.getConstructors();
    

    2、根據參數獲取單個構造方法:getConstructor(參數class…)

    // 運行時拿到Class
    Class fruitClass = Class.forName("com.kproduce.androidstudy.test.Fruit");
    
    // 1、構造方法:Fruit()
    fruitClass.getConstructor();
    
    // 2、構造方法:Fruit(String)
    fruitClass.getConstructor(String.class);
    
    // 3、構造方法:Fruit(int)
    fruitClass.getConstructor(int.class);
    
    // 4、構造方法:Fruit(String, int)
    fruitClass.getConstructor(String.class, int.class);
    

    3、使用構造方法創建對象

    // 構造方法:Fruit(String, int)
    Constructor<Fruit> constructor = fruitClass.getConstructor(String.class, int.class);
    
    // 根據構造方法 Fruit(String, int) 創建對象
    Fruit apple = constructor.newInstance("蘋果", 1);
    

    2.4 獲取類的所有方法

    和獲取構造方法類似,有獲取所有方法和單個方法的API,但是有兩套供選擇,注意注釋的方法限制。

    1、獲取所有方法:

    • getMethods()
    • getDeclaredMethods()
    // 獲取所有方法,包含從父類繼承的,不包括private:
    Method[] methods = fruitClass.getMethods();
    
    // 獲取所有方法,不包含從父類繼承的,包括private:
    Method[] declaredMethods = fruitClass.getDeclaredMethods();
    

    2、根據參數獲取單個方法:

    • getMethod(“方法名”, 參數class…)
    • getDeclaredMethod(“方法名”,參數class…)
    // 獲取單個方法,包含從父類繼承的,不包括private,可添加參數(參數重載)
    fruitClass.getMethod("方法名", 參數class...);
    
    // 獲取單個方法,不包含從父類繼承的,包括private,可添加參數(參數重載)
    fruitClass.getDeclaredMethod("方法名", 參數class...);
    

    3、使用方法

    // 獲取方法
    Method method = fruitClass.getDeclaredMethod("方法名", 參數class...);
    
    // 如果方法是私有的需要加下面這句
    method.setAccessible(true);
    
    // 調用方法,參數是被調用的對象,方法的調用需要基于對象
    method.invoke(constructor.newInstance("蘋果", 1));
    

    2.5 獲取類的成員變量

    和獲取方法基本一致,也有兩套,可以給變量賦值和取值,都是基于對象的。
    1、獲取所有成員變量:

    • getMethods()
    • getDeclaredMethods()
    // 獲取所有變量,包含從父類繼承的,不包括private:
    Field[] fields = fruitClass.getFields();
    
    // 獲取所有變量,不包含從父類繼承的,包括private:
    Field[] declaredFields = fruitClass.getDeclaredFields();
       
    

    2、根據名稱獲取單個成員變量:

    • getField(@NonNull String name)
    • getDeclaredField(@NonNull String var1)
    // 獲取單個成員變量,包含從父類繼承的,不包括private
    Field nameFiled = fruitClass.getField("name");
    
    // 獲取單個成員變量,不包含從父類繼承的,包括private
    Field typeFiled = fruitClass.getDeclaredField("type");
    

    3、給成員變量賦值和獲取值

    // 獲取值和賦值都是基于對象,所以先創建對象
    Fruit apple = constructor.newInstance("蘋果", 1);
    
    // 獲取name的成員變量
    Field nameFiled = fruitClass.getField("name");
    
    // 如果變量是私有的在操作之前需要加下面這句
    nameFiled.setAccessible(true);
    
    // 【取值】獲取name的值,值是“蘋果”
    Object filed = nameFiled.get(apple);
    
    // 【賦值】給apple對象,設置name的值為“香蕉”
    nameFiled.set(apple, "香蕉");
    
    

    總結

    最后咱們再總結一下反射的知識點:

    1. 反射可以在程序的運行時,構造任意一個類的對象、了解任意一個對象所屬的類、了解任意一個類的成員變量和方法、調用任意一個對象的屬性和方法。
    2. 反射的原理是:運行時通過字節碼文件獲取到類的所有信息。
    3. 反射的優點是自由度高,可以無視訪問權限限制。缺點是性能差、安全性差(破壞了類的封裝性)。
    4. 反射需要先在運行時得到類,有四種方式,得到類之后可以了解其中的方法和成員變量。
    5. 反射中對方法的調用、成員變量的取值和賦值,都是基于對象進行操作。

    這樣反射的介紹就結束了,希望大家讀完這篇文章,會對反射有一個更深入的了解。如果我的文章能給大家帶來一點點的福利,那在下就足夠開心了。

    下次再見!

    公眾號

    下面是我的微信公眾號【老匡話Android】,所有的系列文章都會在公眾號同步更新,歡迎關注。

    • 5
      點贊
    • 9
      評論
    • 2
      收藏
    • 一鍵三連
      一鍵三連
    • 掃一掃,分享海報

    打賞
    文章很值,打賞犒勞作者一下
    相關推薦
    DirectX修復工具(DirectX Repair)是一款系統級工具軟件,簡便易用。本程序為綠色版,無需安裝,可直接運行。 本程序的主要功能是檢測當前系統的DirectX狀態,如果發現異常則進行修復。程序主要針對0xc000007b問題設計,可以完美修復該問題。本程序中包含了最新版的DirectX redist(Jun2010),并且全部DX文件都有Microsoft的數字簽名,安全放心。 本程序為了應對一般電腦用戶的使用,采用了易用的一鍵式設計,只要點擊主界面上的“檢測并修復”按鈕,程序就會自動完成校驗、檢測、下載、修復以及注冊的全部功能,無需用戶的介入,大大降低了使用難度。在常規修復過程中,程序還會自動檢測DirectX加速狀態,在異常時給予用戶相應提示。 本程序適用于多個操作系統,如Windows XP(需先安裝.NET 2.0,詳情請參閱“致Windows XP用戶.txt”文件)、Windows Vista、Windows 7、Windows 8、Windows 8.1、Windows 8.1 Update、Windows 10,同時兼容32位操作系統和64位操作系統。本程序會根據系統的不同,自動調整任務模式,無需用戶進行設置。 本程序的V4.0版分為標準版、增強版以及在線修復版。所有版本都支持修復DirectX的功能,而增強版則額外支持修復c++的功能。在線修復版功能與標準版相同,但其所需的數據包需要在修復時自動下載。各個版本之間,主程序完全相同,只是其配套使用的數據包不同。因此,標準版和在線修復版可以通過補全擴展包的形式成為增強版。本程序自V3.5版起,自帶擴展功能。只要在主界面的“工具”菜單下打開“選項”對話框,找到“擴展”標簽,點擊其中的“開始擴展”按鈕即可。擴展過程需要Internet連接,擴展成功后新的數據包可自動生效。擴展用時根據網絡速度不同而不同,最快僅需數秒,最慢需要數分鐘,煩請耐心等待。如擴展失敗,可點擊“擴展”界面左上角小鎖圖標切換為加密連接,即可很大程度上避免因防火墻或其他原因導致的連接失敗。 本程序自V2.0版起采用全新的底層程序架構,使用了異步多線程編程技術,使得檢測、下載、修復單獨進行,互不干擾,快速如飛。新程序更改了自我校驗方式,因此使用新版本的程序時不會再出現自我校驗失敗的錯誤;但并非取消自我校驗,因此程序安全性與之前版本相同,并未降低。 程序有更新系統c++功能。由于絕大多數軟件運行時需要c++的支持,并且c++的異常也會導致0xc000007b錯誤,因此程序在檢測修復的同時,也會根據需要更新系統中的c++組件。自V3.2版本開始使用了全新的c++擴展包,可以大幅提高工業軟件修復成功的概率。修復c++的功能僅限于增強版,標準版及在線修復版在系統c++異常時(非丟失時)會提示用戶使用增強版進行修復。除常規修復外,新版程序還支持C++強力修復功能。當常規修復無效時,可以到本程序的選項界面內開啟強力修復功能,可大幅提高修復成功率。請注意,請僅在常規修復無效時再使用此功能。 程序有兩種窗口樣式。正常模式即默認樣式,適合絕大多數用戶使用。另有一種簡約模式,此時窗口將只顯示最基本的內容,修復會自動進行,修復完成10秒鐘后會自動退出。該窗口樣式可以使修復工作變得更加簡單快速,同時方便其他軟件、游戲將本程序內嵌,即可進行無需人工參與的快速修復。開啟簡約模式的方法是:打開程序所在目錄下的“Settings.ini”文件(如果沒有可以自己創建),將其中的“FormStyle”一項的值改為“Simple”并保存即可。 新版程序支持命令行運行模式。在命令行中調用本程序,可以在路徑后直接添加命令進行相應的設置。常見的命令有7類,分別是設置語言的命令、設置窗口模式的命令,設置安全級別的命令、開啟強力修復的命令、設置c++修復模式的命令、控制Direct加速的命令、顯示版權信息的命令。具體命令名稱可以通過“/help”或“/?”進行查詢。 程序有高級篩選功能,開啟該功能后用戶可以自主選擇要修復的文件,避免了其他不必要的修復工作。同時,也支持通過文件進行輔助篩選,只要在程序目錄下建立“Filter.dat”文件,其中的每一行寫一個需要修復文件的序號即可。該功能僅針對高級用戶使用,并且必須在正常窗口模式下才有效(簡約模式時無效)。 本程序有自動記錄日志功能,可以記錄每一次檢測修復結果,方便在出現問題時,及時分析和查找原因,以便找到解決辦法。 程序的“選項”對話框中包含了7項高級功能。點擊"常規”選項卡可以調整程序的基本運行情況,包括日志記錄、安全級別控制、調試模式開啟等。只有開啟調試模式后才能在C
    ??2020 CSDN 皮膚主題: 大白 設計師:CSDN官方博客 返回首頁

    打賞

    老匡話Android

    你的鼓勵將是我創作的最大動力

    ¥2 ¥4 ¥6 ¥10 ¥20
    輸入1-500的整數
    余額支付 (余額:-- )
    掃碼支付
    掃碼支付:¥2
    獲取中
    掃碼支付

    您的余額不足,請更換掃碼支付或充值

    打賞作者

    實付
    使用余額支付
    點擊重新獲取
    掃碼支付
    錢包余額 0

    抵扣說明:

    1.余額是錢包充值的虛擬貨幣,按照1:1的比例進行支付金額的抵扣。
    2.余額無法直接購買下載,可以購買VIP、C幣套餐、付費專欄及課程。

    余額充值
    多乐彩