Java的動態(tài)代理和靜態(tài)代理及反射常用API詳解
JDK動態(tài)代理
我們看下JDK動態(tài)代理的實現(xiàn)步驟:
第一步:創(chuàng)建接口,JDK動態(tài)代理基于接口實現(xiàn),所以接口必不可少(準備工作)
第二步:實現(xiàn)InvocationHandler接口,重寫invoke方法(準備工作)
第三步:調(diào)用Proxy的靜態(tài)方法newProxyInstance方法生成代理實例(生成實例時需要提供類加載器,我們可以使用接口類的加載器即可)
第四步:使用新生成的代理實例調(diào)用某個方法實現(xiàn)功能。
我們的動態(tài)代理實現(xiàn)過程中根本沒有涉及到真實類實例。
靜態(tài)代理
package ceshi1; public interface Iuser { void eat(String s); }
package ceshi1; public class UserImpl implements Iuser { @Override public void eat(String s) { System.out.println("我要吃"+s); } }
package ceshi1; public class UserProxy implements Iuser { private Iuser user = new UserImpl(); @Override public void eat(String s) { System.out.println("靜態(tài)代理前置內(nèi)容"); user.eat(s); System.out.println("靜態(tài)代理后置內(nèi)容"); } }
package ceshi1; public class ProxyTest { public static void main(String[] args) { UserProxy proxy = new UserProxy(); proxy.eat("蘋果"); } }
動態(tài)代理
package ceshi1; public interface Iuser { void eat(String s); }
package ceshi1; public class UserImpl implements Iuser { @Override public void eat(String s) { System.out.println("我要吃"+s); } }
package ceshi1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class DynamicProxy implements InvocationHandler { private Object object;//用于接收具體實現(xiàn)類的實例對象 //使用帶參數(shù)的構(gòu)造器來傳遞具體實現(xiàn)類的對象 public DynamicProxy(Object obj){ this.object = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args)throws Throwable { System.out.println("前置內(nèi)容"); method.invoke(object, args); System.out.println("后置內(nèi)容"); return null; } }
package ceshi1; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class ProxyTest { public static void main(String[] args) { Iuser user = new UserImpl(); InvocationHandler h = new DynamicProxy(user); Iuser proxy = (Iuser) Proxy.newProxyInstance(Iuser.class.getClassLoader(), new Class[]{Iuser.class}, h); proxy.eat("蘋果"); } }
反射
JDK 提供的反射 API 進行反射調(diào)用:
Class clz = Class.forName("com.chenshuyi.reflect.Apple"); Method method = clz.getMethod("setPrice", int.class); Constructor constructor = clz.getConstructor(); Object object = constructor.newInstance(); method.invoke(object, 4);
一般情況下我們使用反射獲取一個對象的步驟:
獲取類的 Class 對象實例
Class clz = Class.forName("com.zhenai.api.Apple");
根據(jù) Class 對象實例獲取 Constructor 對象
Constructor appleConstructor = clz.getConstructor();
使用 Constructor 對象的 newInstance 方法獲取反射類對象
Object appleObj = appleConstructor.newInstance();
而如果要調(diào)用某一個方法,則需要經(jīng)過下面的步驟:
獲取方法的 Method 對象
Method setPriceMethod = clz.getMethod("setPrice", int.class);
利用 invoke 方法調(diào)用方法
setPriceMethod.invoke(appleObj, 14);
反射常用API
在 Java API 中,獲取 Class 類對象有三種方法:
第一種,使用 Class.forName 靜態(tài)方法。當你知道該類的全路徑名時,你可以使用該方法獲取 Class 類對象。
Class clz = Class.forName("java.lang.String");
第二種,使用 .class 方法。
這種方法只適合在編譯前就知道操作的 Class。
Class clz = String.class;
第三種,使用類對象的 getClass() 方法。
String str = new String("Hello"); Class clz = str.getClass();
通過反射創(chuàng)建類對象
通過反射創(chuàng)建類對象主要有兩種方式:通過 Class 對象的 newInstance() 方法、通過 Constructor 對象的 newInstance() 方法。
第一種:通過 Class 對象的 newInstance() 方法。
Class clz = Apple.class; Apple apple = (Apple)clz.newInstance();
第二種:通過 Constructor 對象的 newInstance() 方法
Class clz = Apple.class; Constructor constructor = clz.getConstructor(); Apple apple = (Apple)constructor.newInstance();
通過 Constructor 對象創(chuàng)建類對象可以選擇特定構(gòu)造方法,而通過 Class 對象則只能使用默認的無參數(shù)構(gòu)造方法。下面的代碼就調(diào)用了一個有參數(shù)的構(gòu)造方法進行了類對象的初始化。
Class clz = Apple.class; Constructor constructor = clz.getConstructor(String.class, int.class); Apple apple = (Apple)constructor.newInstance("紅富士", 15);
我們通過 Class 對象的 getFields() 方法可以獲取 Class 類的屬性,但無法獲取私有屬性。
Class clz = Apple.class; Field[] fields = clz.getFields(); for (Field field : fields) { System.out.println(field.getName()); }
而如果使用 Class 對象的 getDeclaredFields() 方法則可以獲取包括私有屬性在內(nèi)的所有屬性:
Class clz = Apple.class; Field[] fields = clz.getDeclaredFields(); for (Field field : fields) { System.out.println(field.getName()); }
到此這篇關(guān)于Java的動態(tài)代理和靜態(tài)代理及反射常用API詳解的文章就介紹到這了,更多相關(guān)Java動態(tài)代理和反射內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis注解方式之@Update/@Delete使用詳解
這篇文章主要介紹了MyBatis注解方式之@Update/@Delete使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11深入理解JVM之Java對象的創(chuàng)建、內(nèi)存布局、訪問定位詳解
這篇文章主要介紹了深入理解JVM之Java對象的創(chuàng)建、內(nèi)存布局、訪問定位,結(jié)合實例形式詳細分析了Java對象的創(chuàng)建、內(nèi)存布局、訪問定位相關(guān)概念、原理、操作技巧與注意事項,需要的朋友可以參考下2019-09-09springboot3.x版本集成log4j遇到Logging?system?failed?to?initial
使用Springboot?3.x集成Log4j時可能會遇到版本沖突的問題,這通??梢酝ㄟ^檢查Maven依賴樹來識別,一旦發(fā)現(xiàn)沖突,將Log4j的版本統(tǒng)一更新到最新的兼容版本,例如2.21.1,即可解決問題,此方法有效解決了日志打印錯誤,是處理類似問題的一個實用參考2024-09-09mybatis-plus報錯net.sf.jsqlparser.statement.select.SelectBody的
本文主要介紹了mybatis-plus報錯net.sf.jsqlparser.statement.select.SelectBody的問題解決,具有一定的參考價值,感興趣的可以了解一下2024-08-08SpringBoot Pom文件依賴及Starter啟動器詳細介紹
這篇文章主要介紹了SpringBoot Pom文件的依賴與starter啟動器的作用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-09-09