Java反射機制能夠動態地獲取類的結構,動態地調用對象的方法,是java語言一個動態化的機制。java動態代理能夠在不改變被調用對象源碼的前提下,在被調用方法先後增長本身的操做,極大地下降了模塊之間的耦合性。這些都是java的基礎知識,要想成爲一名合格的程序猿,必須掌握!java
JAVA反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。 ide
Java反射機制容許程序在運行時判斷分析任意一個類的結構,包括成員變量和方法,並調用任意一個對象的方法。Eclipse能夠自動彈出對象的方法及屬性,就是利用了反射的原理。Java的動態代理就是利用了反射的特性來實現的。函數
一、獲取類Class對象this
1) A.class :不會加載類,也不會執行靜態代碼段;spa
2) Class.forName("cn.test.reflect.A") :要求JVM查找並加載指定的類,也就是說JVM會執行該類的靜態代碼段;代理
3) new A().getClass() :經過對象獲取class日誌
二、反射建立對象code
1) 經過默認構造函數建立對象:Class<?> t = Class.forName("cn.test.reflect.A"); t.newInstance();htm
2) 經過指定構造函數建立對象:Class<?> t = Class.forName("cn.test.reflect.A"); Constructor<?> cons[] = t.getConstructors(); A a = (A) cons[2].newInstance("aa","bb");對象
注:
① Class<?>表示任何類型的類;
② newInstance()方法只能調用public的無參構造函數,它和new關鍵字建立實例的區別:建立對象的方式不同,前者是使用類加載機制,後者是建立一個新類;
三、Class類經常使用方法
▶ getName() :得到類的完整名字;
▶ getSuperclass() :得到類的父類;
▶ newInstance() :經過類的不帶參數的構造方法建立這個類的一個對象;
▶ getFields() :得到當前類和父類中的public類型的全部屬性;
▶ getDeclaredFields() :得到當前類(不包含父類)聲明的全部屬性,包括private和public;
注:對於某個屬性field,設置field.setAccessible(true),便可訪問private的屬性值,如field.get(obj)
▶ getMethods() :得到前類和父類中public類型的全部方法;
▶ getDeclaredMethods() :得到當前類(不包含父類)聲明的全部方法,包括private和public;
▶ getMethod(String name, Class[] parameterTypes) :得到類的指定方法,name參數指定方法的名字,parameterTypes 參數指定方法的參數類型;
▶ getConstructors() :得到當前類的public類型的構造方法;
▶ getDeclaredConstructors() :得到當前類的public和private類型的構造方法;
▶ getConstructor(Class[] parameterTypes) :得到類的特定構造方法,parameterTypes 參數指定構造方法的參數類型;
▶ getInterfaces() :得到實現的接口;
▶ getSuperclass() :得到繼承的父類;
四、Java反射使用實例
package com.hicoor.test.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; class B{ public int b; public B(){} } interface IA{} class A extends B implements IA{ public A() { } public A(String str) { } public A(String str1, String str2) { } private String str; public int age; public int func1(String name) { System.out.println("hello " + name); return 8; } public void func1(String name1, String name2) { System.out.println("hello "+name1+","+name2); } } public class ReflectDemo { public static void main(String[] args) throws Exception { // 根據字符串得到類 Class<?> demoClass = Class.forName("com.hicoor.test.reflect.A"); // 得到類的完整名字 System.out.println("類名"+demoClass.getName()); // com.hicoor.test.reflect.A // 得到類加載器,默認sun.misc.Launcher$AppClassLoader System.out.println("類加載器:"+demoClass.getClassLoader().getClass().getName()); //根據Class的共有無參構造方法建立一個實例 A newAObj = (A)demoClass.newInstance(); // 得到類中聲明的屬性 Field[] publicFields = demoClass.getFields(); // 得到當前類和父類中的public類型的全部屬性,返回:age Field[] declareFields = demoClass.getDeclaredFields(); // 得到當前類(不包含父類)聲明的全部屬性,包括private和public,返回:str age Field specifyField = demoClass.getField("age"); // 根據名稱獲取指定屬性 specifyField.setAccessible(true); //修改屬性 specifyField.set(newAObj, 88); // 得到類的方法 Method[] publicMethods = demoClass.getMethods(); // 得到前類和父類中public類型的全部方法 Method[] declareMethods = demoClass.getDeclaredMethods(); // 得到當前類(不包含父類)聲明的全部方法,包括private和public Method specifyMethod = demoClass.getDeclaredMethod("func1",new Class<?>[]{java.lang.String.class}); //根據方法名和方法參數類型指定獲取一個方法 //反射調用對象的方法 specifyMethod.invoke(newAObj, "hans"); //得到構造函數 Constructor<?>[] publicConstructors = demoClass.getConstructors(); Constructor<?>[] declareConstructors = demoClass.getDeclaredConstructors(); //得到當前類聲明的全部private和public構造方法 Constructor<?> constructor = demoClass.getConstructor(new Class<?>[]{java.lang.String.class}); //根據指定類型得到構造方法 A newAobj2 = (A)constructor.newInstance("hello"); //根據指定構造函數建立實例 //得到實現的接口 Class<?>[] interfaces = demoClass.getInterfaces(); //得到繼承的父類 Class<?> superclass = demoClass.getSuperclass(); } //反射得到一個方法的明細定義 private static void getMethodDetail(Method method) { String methodModifier = Modifier.toString(method.getModifiers()); //方法修飾符 String returnType = method.getReturnType().getName(); //方法返回值 Class<?>[] parameterTypes = method.getParameterTypes(); //方法參數類型 System.out.print(methodModifier+" "+returnType+" "+ method.getName()+"("); int i=1; for (Class<?> parameterType : parameterTypes) { System.out.print(parameterType.getName() + " arg"+(i++)); if(i<=parameterTypes.length){ System.out.print(","); } } System.out.println(") {}"); } }
假若有這樣的需求,要在某些模塊方法調用先後加上一些統一的先後處理操做,好比在添加購物車、修改訂單等操做先後統一加上登錄驗證與日誌記錄處理,該怎樣實現?首先想到最簡單的就是直接修改源碼,在對應模塊的對應方法先後添加操做。若是模塊不少,你會發現,修改源碼不只很是麻煩、難以維護,並且會使代碼顯得十分臃腫。
這時候就輪到動態代理上場了,它能夠經過反射在被調用方法先後加上本身的操做,而不須要更改被調用類的源碼,大大地下降了模塊之間的耦合性,體現了極大的優點。
一、JDK動態代理
JDK動態代理中包含一個類和一個接口,即Proxy類和InvocationHandler接口。
1) InvocationHandler接口:
public interface InvocationHandler { public Object invoke(Object proxy,Method method,Object[] args) throws Throwable; }
參數說明:① Object proxy:指被代理的對象;② Method method:要調用的方法;③ Object[] args:方法調用時所須要的參數;
2) Proxy類: Proxy類是專門完成代理的操做類,能夠經過此類爲一個或多個接口動態地生成實現類,此類提供了以下的操做方法。
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
參數說明:① ClassLoader loader:類加載器;② Class<?>[] interfaces:獲得所有的接口;③ InvocationHandler h:獲得InvocationHandler接口的子類實例 ;
3) 關於類加載器
在Proxy類中的newProxyInstance()方法中須要一個ClassLoader類的實例,ClassLoader實際上對應的是類加載器,在Java中主要有如下三種類加載器:
① Booststrap ClassLoader:此加載器採用C++編寫,一般加載jre/lib/rt.jar,通常開發中是看不到的;
② Extendsion ClassLoader:用來進行擴展類的加載,一般加載jre/lib/ext/*.jar;
③ AppClassLoader:(默認)加載classpath指定的類,是最常使用的是一種加載器;
4) JDK動態代理實例:
package com.hicoor.test.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Animal { public void makeSound(String name); } class Dog implements Animal { @Override public void makeSound(String name) { System.out.println("Hi," + name + ",wang,wang~~"); } } class Cat implements Animal { @Override public void makeSound(String name) { System.out.println("Hi," + name + ",miao,miao~~"); } } /** * @author Hans 通用動態代理類,被調用對象方法先後增長特殊操做同樣的類可都用此類代理 */ class AnimalProxy implements InvocationHandler { // 要代理的對象 private Object target; /** * 綁定委託對象並返回一個代理類 * * @param target * @return */ public Object getInstance(Object target) { this.target = target; // 取得代理對象 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; System.out.println("方法調用前操做.."); // 執行被調用方法主體 result = method.invoke(target, args); System.out.println("方法調用後操做.."); return result; } } public class DynamicProxyJDKDemo { public static void main(String[] args) { AnimalProxy proxy = new AnimalProxy(); Animal dogProxy = (Animal) proxy.getInstance(new Dog()); dogProxy.makeSound("Tom"); } }
二、Cglib動態代理
JDK的動態代理機制只能代理實現了接口的類,而不能實現接口的類就不能實現JDK的動態代理,cglib是針對類來實現代理的,他的原理是對指定的目標類生成一個子類,並覆蓋其中方法實現加強,但由於採用的是繼承,因此不能對final修飾的類進行代理。
使用cglib代理需下載cglib.jar文件,下載地址:http://www.java2s.com/Code/Jar/c/Downloadcloudcglibjar.htm
Cglib動態代理實例:
package com.hicoor.test.dynamicProxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; class Snake{ public void makeSound(String name) { System.out.println("Hi," + name + ",si,si~~"); } } class AnimalProxyCglib implements MethodInterceptor { // 要代理的對象 private Object target; /** * 建立代理對象 * * @param target * @return */ public Object getInstance(Object target) { this.target = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(this.target.getClass()); // 回調方法 enhancer.setCallback(this); // 建立代理對象 return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { Object result = null; System.out.println("方法調用前操做.."); // 執行被調用方法主體 result = proxy.invokeSuper(obj, args); System.out.println("方法調用後操做.."); return result; } } public class DynamicProxyCglibDemo { public static void main(String[] args) { AnimalProxyCglib proxy = new AnimalProxyCglib(); Snake dogProxy = (Snake) proxy.getInstance(new Snake()); dogProxy.makeSound("Tom"); } }