Java中反射的使用詳解

1. 簡介

反射可以動態(tài)獲取類的完整結構信息,調用對象的方法。

  1. 優(yōu)點:靈活性高,只有在運行時才動態(tài)創(chuàng)建對象實例
  2. 缺點:
    1. 反射獲取方法時是通過獲取所有方法,然后獲得的,時間開銷較高
    2. 方法調用invoke()時傳入的是object和object[]。不管什么類型都會轉為object會生成對象,同時object[]還需要額外的封裝,遍歷,裝箱開箱等性能消耗
    3. 每次調用方法都會檢查方法等可見性,也必須檢查參數(shù)等類型是否匹配
    4. 方法難以內聯(lián)優(yōu)化
    5. 反射是動態(tài)加載,無法JIT優(yōu)化(編譯執(zhí)行才會用到JIT)
    6. 反射會破壞類結構,干擾類原有的內部邏輯。

2. 反射的使用

  1. 獲取Class對象:

    //方式一:類名.class方式       
    Class<ReflectionDemo> reflectionDemoClass = ReflectionDemo.class;
    //方式二:對象.getClass()方式
    ReflectionDemo newReflectionDemo = new ReflectionDemo();
    Class<? extends ReflectionDemo> getReflectionDemo = newReflectionDemo.getClass();
    //方式三:Class.forName(包名.類名)方式
    Class<?> forNamereflectionDemo = Class.forName("xxx.xxx.ReflectionDemo");
    
  2. 獲取構造方法Constructor:

        private static void ConstructorTest(Class c){
            try {
                //獲取指定參數(shù)的構造方法,不傳參則獲取午餐構造。只能獲取public修飾的方法
                Constructor constructor = c.getConstructor(int.class);
                //獲取所有的構造,只能獲取public修飾的方法
                Constructor[] constructors = c.getConstructors();
              
                //獲取指定參數(shù)的構造方法,不傳參則獲取午餐構造。可以獲取所有修飾符修飾的方法
                Constructor declaredConstructor = c.getDeclaredConstructor(int.class);
                //獲取所有的構造。可以獲取所有修飾符修飾的方法
                Constructor[] declaredConstructors = c.getDeclaredConstructors();
                 //獲取此構造是哪個類的構造
                 Class declaringClass = constructor.getDeclaringClass();
            }catch (Exception e){
            }
    
        }
    
    • 獲取單個構造方法時,如果有參數(shù),需要傳入?yún)?shù)類型.class,多個參數(shù)時按順序填寫多個,無參不傳。
    • 獲取構造方法名字不帶Declared的,只能獲取被public修飾的方法。
    • 獲取方法名字不帶Declared的,可以獲取任何修飾符修飾的方法。
    • 通過getDeclaringClass()獲取當前構造方法是哪個類的構造
  3. 獲取類的屬性Field:

         private static void filedTest(Class c){
            try {
                         //獲取指定的成員變量。傳入成員變量名。只能獲取public修飾的成員變量,可以獲取繼承的父類的成員變量
                Field field = c.getField("reflectionInt");
                         //獲取所有的成員變量。只能獲取public修飾的成員變量,可以獲取父類的成員變量
                Field[] fields = c.getFields();
                         //獲取指定的成員變量。傳入成員變量名??梢垣@取所有修飾符修飾的成員變量,不可以獲取繼承的父類的成員變量
                Field reflectionInt = c.getDeclaredField("reflectionInt");
                         //獲取所有的成員變量??梢垣@取所有修飾符修飾的成員變量,不可以獲取父類的屬性
                Field[] declaredFields = c.getDeclaredFields();
                 //構造一個對象
                ReflectionDemo reflectionDemo = new ReflectionDemo();
                         //通過field字段獲取這個對象這個成員變量的值
                //如果對象被private修飾必須設置field.setAccessible(true),否則無法訪問get(),會報錯
               field.setAccessible(true);
                Object o = field.get(reflectionDemo);
                 //通過field字段設置這個對象這個成員變量的值
                field.set(reflectionDemo,10);
                 //獲取此屬性是哪個類的成員變量,這里返回的是ReflectionDemo
                   Class<?> declaringClass = field.getDeclaringClass();
           }
    
    • 獲取單個成員變量時,需要傳入成員變量名
    • 獲取方法名字不帶Declared的,只能獲取被public修飾的成員變量,可以獲取自身及父類的成員變量。
    • 獲取方法名字不帶Declared的,可以獲取任何修飾符修飾的成員變量,但是只能獲取自身的成員變量,不能獲取父類的成員變量。
    • getField("字段名")獲取的是成員變量,而不是具體的值。可以通過獲取的field.get("對象"),獲取某個對象的這個成員變量的值。如果對象被private修飾則必須設置field.setAccessible(true),否則get()時會出錯
    • 可以通過獲取的成員變量field.set(對象,字段值),來設置某個對象的某個成員變量的值
    • 通過getDeclaringClass()獲取當前成員變量是哪個類的成員變量。(同一個類的成員變量調用此方法返回值是一樣的)
  4. 獲取類的方法Method:

        private static void methodTest(Class c) {
            try {
                //獲取指定方法,第一個參數(shù)為方法名,第二個為參數(shù)類型的Class,多個參數(shù)的話,按順序排列。只能獲取public修飾的方法,可以獲取繼承的父類的public方法
                Method method = c.getMethod("reflectionTest", int.class);
                //獲取所有方法,只能獲取public修飾的方法,可以獲取繼承的父類的public方法
                Method[] methods = c.getMethods();
              
                //獲取指定方法,第一個參數(shù)為方法名,第二個為參數(shù)類型的Class,多個參數(shù)的話,按順序排列。能獲取所有的方法,不可以獲取繼承的父類的public方法
                Method reflectionTest = c.getDeclaredMethod("reflectionTest", int.class);
                //獲取所有方法,能獲取所有的方法,不可以獲取繼承的父類的public方法
                Method[] declaredMethods = c.getDeclaredMethods();
                 //調用invoke()執(zhí)行方法,第一個參數(shù)為執(zhí)行方法的對象,第二個參數(shù)為要設置的方法的參數(shù)值
                 //如果方法被private修飾則必須設置method.setAccessible(true),否則報錯
                 method.setAccessible(true);
                 method.invoke(reflectionDemo,9);
                 //獲取此方法是哪個類的方法
                Class<?> declaringClass = method.getDeclaringClass();
            } catch (Exception e) {
    
            }
    
    • 獲取單個方法時,需要傳入方法名,如果有參數(shù),還需要參數(shù)類型.class,多個參數(shù)時按順序填寫多個。
    • 獲取方法名字不帶Declared的,只能獲取被public修飾的方法,可以獲取自身及父類的public的方法。
    • 獲取方法名字不帶Declared的,可以獲取任何修飾符修飾的方法,但是只能獲取自身的方法,不能獲取父類的方法。如果重寫了父類的方法,那么就可以獲取。
    • 調用invoke()執(zhí)行方法,第一個參數(shù)為執(zhí)行方法的對象,第二個參數(shù)為要設置的方法的參數(shù)值,多個參數(shù)直接寫多個。如果方法被private修飾則必須設置method.setAccessible(true),否則報錯。
    • 通過getDeclaringClass()獲取當前方法是哪個類的方法。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容