您好,登錄后才能下訂單哦!
本篇內容介紹了“如何理解Java反射技術”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
Java 反射機制在程序運行時,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個對象,都能夠調用它的任意一個方法和屬性。這種 動態的獲取信息 以及 動態調用對象的方法 的功能稱為 java 的反射機制。反射中的反的理解:在使用的之前,提前不知道需要使用什么類型的對象。只是在調用的時候,才知道要調用的對象類型。這種反其道而行的就是反射中反的理解。程序執行分為編譯器和運行期,編譯時刻加載一個類就稱為靜態加載類,運行時刻加載類稱為動態加載類,核心思想 讓你在寫代碼的時候可以更加靈活,降低耦合,提高代碼的自適應能力。反射框架提供如下常用的核心功能:1.在運行時判斷任意對象所屬的類;2.在運行時構造任意一個類的對象;3.在運行時判斷任意一個類所具有的成員變量和方法(通過反射甚至可以調用private方法);4.在運行時調用任意一個對象的方法;
通用框架,很多框架都是配置化的(比如Spring通過xml配置Bean), 為了保證框架的通用性,可能需要根據不同的配置文件加載不同的對象或者類,調用不同的方法,這個時候就需要反射,運行時動態加載需要加載的對象。
· 性能不佳 - 由于java反射動態解析類型,因此涉及掃描類路徑以查找要加載的類的處理,從而導致性能降低。
· 安全限制 - Reflection需要運行時權限,這些權限可能不適用于在安全管理器下運行的系統。由于安全管理器,這可能導致應用程序在運行時失敗。
· 安全問題 - 使用反射,我們可以訪問我們不應該訪問的部分代碼,例如,我們可以訪問類的私有字段并更改它的值。這可能是嚴重的安全威脅,并導致您的應用程序出現異常行為。
· 高維護 - 反射代碼很難理解和調試,在編譯時也無法找到代碼的任何問題,因為這些類可能不可用,使其不太靈活且難以維護。
00001. Class 對象
00002. 類名
00003. 修飾符
00004. 包信息
00005. 父類
00006. 實現的接口
00007. 構造器
00008. 方法
00009. 變量
00010. 注解
在運行期間,一個類,只有一個Class對象產生
00001. 說明獲取指定的類完整的路徑相關聯類或接口的Class對象。
00002. 方法// 掌握public static Class<?> forName(String className)// 了解public static Class<?> forName(String className, boolean initialize,ClassLoader loader)
00003. 舉個栗子Class clazz = Class.forName("http://com.wener.reflect.Xxx")// 或者 Class clazz = Class.forName("http://com.wener.reflect.Xxx",initialize,this.getClass().getClassLoader)
1. 說明任何數據類型(包括基本數據類型)都有一個“靜態”的class屬性
2. 方法Class<?> cls = 類型.class;
3. 舉個栗子Class<String> cls = String.class;System.out.println(cls.toString());
1. 說明通過對象的實例來返回Class對象
2. 方法Class<?> cls = instance.getClass()
3. 舉個栗子public class User {}User user = new User();Class<? extends User> clz = user.getClass();
1. 方法// 通過字段名,返回一個具體的具有public屬性的成員變量(包括父類的)Field getField(String name) // 通過字段名所有已聲明的所有成員變量(私有的 默認的 共有的),但不能得到其父類的成員變量Field getDeclaredField(String name)
2. 舉個栗子public class User {private String name;public String detail;}public static void main(String[] args) {try {Class<?> cls = Class.forName("com.wener.reflect.demo1.User");/*** 獲取類的指定名稱公開的屬性*/Field detail = cls.getField("detail");System.out.println(detail);/*** 獲取類的指定名稱的的屬性(包括私有的屬性)*/Field name = cls.getDeclaredField("name");System.out.println(name);} catch (ClassNotFoundException | NoSuchFieldException e) {e.printStackTrace();}}
1. 說明反射非常強大,但是學習了之后,會不知道該如何使用,反而覺得還不如直接調用方法來的直接和方便。但等我們后面接觸到一些框架之后才會有一些感觸
2. 測試類package com.wener.reflect.demo2; public class ReflectDemo1 { public void say() { System.out.println("ReflectDemo1"); } } public class ReflectDemo2 { public void say() { System.out.println("ReflectDemo2"); } }
3. 配置文件reflect.propertiesclass=ReflectDemo2. method=say
4. 測試代碼public static void main(String[] args) { //從spring.txt中獲取類名稱和方法名稱 File springConfigFile = new File("/Users/zhangwei/work/IdeaProjects/JavaExample/ReflectExample/src/reflect.properties"); Properties properties = new Properties(); try { properties.load(new FileInputStream(springConfigFile)); String className = (String) properties.get("class"); String methodName = (String) properties.get("method"); //根據類名稱獲取類對象 Class cls = Class.forName(className); //根據方法名稱,獲取方法對象 Method m = cls.getMethod(methodName); //根據構造器,實例化出對象 Object service = cls.newInstance(); //調用對象的指定方法 m.invoke(service); } catch (IOException | InvocationTargetException | NoSuchMethodException | IllegalAccessException | ClassNotFoundException | InstantiationException e) { e.printStackTrace(); } }
5. 優點當需要從調用第一個類的方法,切換到調用第二類的方法的時候,不需要修改一行代碼
1、通過配置文件動態切換六、綜合案例返回值 方法說明String getName()獲取方法的名稱int getModifiers()獲取方法的修飾符Class<?> getReturnType() Type getGenericReturnType返回方法的返回值類型Class<?>[] getParameterTypes() Type[] getGenericParameterTypes()返回方法的參數(列表)Class<?>[] getExceptionTypes() Type[] getGenericExceptionTypes()返回方法的異常信息4、其它API
1. 舉個栗子public class User { private String name = "木木"; public String detail = "hello"; private int age; private BigDecimal balance; public void increment() { this.age++; System.out.println(age); } public BigDecimal getBalance() { return balance; } public void setBalance(BigDecimal balance) { this.balance = balance; } private void say(int num) { System.out.println(num + "號技師"); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", detail='" + detail + '\'' + '}'; } } public class TestReflectUser { public static void main(String[] args) { reflectMethod(); } public static void reflectMethod() { try { // 1.實例化class對象 Class<?> cls = Class.forName("com.wener.reflect.demo1.User"); // 2.實例化User對象 Object o = cls.newInstance(); // 3.獲取set方法 Method method = cls.getMethod("increment"); // 4 執行方法 method.invoke(o); // 有參數無返回值 Method setBalance = cls.getMethod("setBalance", BigDecimal.class); Object methodSet = setBalance.invoke(o, new BigDecimal(100.00)); System.out.println(methodSet); // 有返回值值無參數 Method methodGet = cls.getMethod("getBalance"); Object invoke = methodGet.invoke(o); System.out.println(invoke); // 獲取私有的方法 Method say = cls.getDeclaredMethod("say", int.class); // 運行時取消訪問權限檢測機制 say.setAccessible(true); // 執行方法 say.invoke(o, 1); } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } }
使用參數 args 在 obj 上指派該對象所表示方法的結果
1. 方法Object invoke(Object obj, Object... args)
2. 參數說明
· obj - 從中調用底層方法的對象,必須是實例化的對象
· args - 用于方法調用的參數,是個Object數組,因為參數有可能有多個
1. 返回值
3、調用方法
1. 方法// 返回類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 public Method[] getDeclaredMethods() throws SecurityException// 返回某個類的所有公用(public)方法,包括其繼承類的公用方法。 public Method[] getMethods() throws SecurityException
2. 舉個栗子public class TestReflectUser { public static void main(String[] args) { reflectMethod(); } public static void reflectMethod() { try { // 1.實例化class對象 Class<?> cls = Class.forName("com.wener.reflect.demo1.User"); // 2.實例化User對象 Object o = cls.newInstance(); // 獲取所有的共有的方法(包括父類的方法) Method[] methods = cls.getMethods(); for (Method method1 : methods) { System.out.println(method1.getName()); } // 獲取所有的方法(包括私有的,共有的,默認的) Method[] declaredMethods = cls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod.getName()); } } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } }
2、獲取所有的方法
1. 方法// 方法返回一個特定的方法,其中第一個參數為方法名稱,后面的參數為方法的參數對應Class的對象 public Method getMethod(String name, Class<?>... parameterTypes)
2. 舉個栗子public class User { private String name = "木木"; public String detail = "hello"; private int age; private BigDecimal balance; public void increment() { this.age++; System.out.println(age); } public BigDecimal getBalance() { return balance; } public void setBalance(BigDecimal balance) { this.balance = balance; } private void say(int num) { System.out.println(num + "號技師"); } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", detail='" + detail + '\'' + '}'; } } public class TestReflectUser { public static void main(String[] args) { reflectMethod(); } public static void reflectMethod() { try { // 1.實例化class對象 Class<?> cls = Class.forName("com.wener.reflect.demo1.User"); // 2.實例化User對象 Object o = cls.newInstance(); // 3.獲取increment方法 Method method = cls.getMethod("increment"); // 有參數無返回值 Method setBalance = cls.getMethod("setBalance", BigDecimal.class); // 有返回值值無參數 Method methodGet = cls.getMethod("getBalance"); // 獲取私有的方法 Method say = cls.getDeclaredMethod("say", int.class); } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } } }
1、獲取單個方法五、方法操作
1. 方法// 將指定對象參數上的此Field對象表示的字段設置為指定的新值 field.set(Object obj,Object value)
2. 參數說明
· Object obj: 字段所在的類的實例對象
· Object value : 新值
1. 注意// 如果要給私有變量賦值必須取消權限的訪問控制 field.setAccessible(true);
2. 舉個栗子public static void main(String[] args) { try { // 1 實例化Class對象 Class<?> cls = Class.forName("com.wener.reflect.demo1.User"); /** * 獲取類的指定名稱公有的屬性 */ Field detail = cls.getField("detail"); System.out.println(detail); /** * 獲取類的所有的屬性(包括私有 默認的 公有的) */ Field name = cls.getDeclaredField("name"); // 2.創建對象 Object o = cls.newInstance(); // 3 通過字段的set方法設置 name.set(o, "嬌嬌"); System.out.println(o.toString()); } catch (ClassNotFoundException | NoSuchFieldException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } }
4、字段賦值
1. 方法// 獲取所有的”公有字段” Field[] getFields() // 獲取所有字段(私有、受保護、默認、公有) Field[] getDeclaredFields()
2. 舉個栗子public class TestReflectUserField { public static void main(String[] args) { try { Class<?> cls = Class.forName("com.wener.reflect.demo1.User"); Field[] fields = cls.getFields(); for (Field field : fields) { System.out.println("類型: " + field.getType() + "方法名: " + field.getName()); } Field[] declaredFields = cls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("類型: " + declaredField.getType() + "方法名: " + declaredField.getName()); } } catch (ClassNotFoundException | NoSuchFieldException | InstantiationException | IllegalAccessException e) { e.printStackTrace(); } } }
3、獲取所有成員字段
2、獲取單個成員字段類的成員變量也是一個對象,它是java.lang.reflect.Field的一個對象,所以我們通過java.lang.reflect.Field里面封裝的方法來獲取這些信息并且操作這些屬性1、說明四、屬性操作
1. cls.newInstance()方法返回的是一個泛型T,我們要強轉成自定義類
2. cls.newInstance()默認返回的是類的無參數構造對象
3. 被反射機制加載的類必須有無參數構造方法,否者運行會拋出異常
1.4、注意三、創建實例
1. 常用的是類的靜態方法,
2. getClass()的話一般在繼承的時候用的比較多一點,比如Android里的注解框架
3. .class 靜態語法: 需要導入類的包,依賴太強,不導包就拋編譯錯誤
“如何理解Java反射技術”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。