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