反射機制是在運行狀態中,對於任意一個類,都可以知道這個類的全部屬性和方法;對於任意一個對象,都可以調用它的任意一個方法和屬性。java
在運行時判斷任意一個對象所屬的類
在運行時構造任意一個類的對象
在運行時判斷任意一個類所具備的成員變量和方法
在運行時調用任意一個對象的方法
生成動態代理
反向工程 .class -> .java數組前提是在運行時,不是編譯時,也就是在運行前並不知道調用哪個類,經過反射就能夠作到這些 安全
java.lang.Class
java.lang.reflect.Constructor
java.lang.reflect.Field
java.lang.reflect.Method
java.lang.reflect.Modifier框架
public class MyReflection { // 屬性方法省略 public static void main(String[] arg) throws ClassNotFoundException { //第一種方式: Class c1 = Class.forName("refelection.MyReflection"); //第二種方式:每一個類都有 .class Class c2 = MyReflection.class; //第三種方式: Class c3 = new MyReflection().getClass(); } }
public static void main(String[] arg) throws ClassNotFoundException { Class c1 = Class.forName("refelection.MyReflection"); Class c2 = MyReflection.class; Class c3 = new MyReflection().getClass(); Field[] fs1 = c1.getDeclaredFields(); Field[] fs2 = c2.getFields(); Method[] method1 = c1.getDeclaredMethods(); Method[] method2 = c2.getMethods(); Constructor[] cts1 = c1.getDeclaredConstructors(); Constructor[] cts12 =c2.getDeclaredConstructors(); for(Field field:fs1){ System.out.println("** get declaredFields **"); System.out.println(Modifier.toString(field.getModifiers())); System.out.println( field.getType().getSimpleName()); System.out.println( field.getName()); } for(Field field:fs2){ System.out.println("** get getFields **"); System.out.println(Modifier.toString(field.getModifiers())); System.out.println( field.getType().getSimpleName()); System.out.println( field.getName()); } for(Method method:method1){ System.out.println("** get getDeclaredMethods **"); System.out.println(Modifier.toString(method.getModifiers())); System.out.println( method.getName()); } for(Method method:method2){ System.out.println("** get getMethods **"); System.out.println(Modifier.toString(method.getModifiers())); System.out.println( method.getName()); } for(Constructor constructor:cts1){ System.out.println("** get getDeclaredConstructors **"); System.out.println(Modifier.toString(constructor.getModifiers())); System.out.println( constructor.getName()); } for(Constructor constructor:cts12){ System.out.println("** get getConstructors **"); System.out.println(Modifier.toString(constructor.getModifiers())); System.out.println( constructor.getName()); } }
* getFields()與getDeclaredFields()區別:getFields()只能訪問類中聲明爲公有的字段,私有的字段它沒法訪問,能訪問從其它類繼承來的公有方法.getDeclaredFields()能訪問類中全部的字段,與public,private,protect無關,不能訪問從其它類繼承來的方法 函數
* getMethods()與getDeclaredMethods()區別:getMethods()只能訪問類中聲明爲公有的方法,私有的方法它沒法訪問,能訪問從其它類繼承來的公有方法.getDeclaredFields()能訪問類中全部的字段,與public,private,protect無關,不能訪問從其它類繼承來的方法 this
* getConstructors()與getDeclaredConstructors()區別:getConstructors()只能訪問類中聲明爲public的構造函數.getDeclaredConstructors()能訪問類中全部的構造函數,與public,private,protect無關 spa
獲取指定屬性與獲取所有屬性的方法相似 而且一一對應,方法名沒有S之外,返回的對象是具體對象而不是數組了。代理
//獲取類 Class c = Class.forName("User"); //獲取id屬性 Field idF = c.getDeclaredField("id");
類方法有一些是私有的,反射機制提供了setAccessiable(true)方法,打破封裝性,這樣能夠經過反射解析一些私有方法,如讀取,賦值等。 顯然這是一個不安全的操做。code
//獲取類 Class c = Class.forName("User"); //獲取id屬性 Field idF = c.getDeclaredField("id"); //實例化這個類賦給o Object o = c.newInstance(); //打破封裝 idF.setAccessible(true); //使用反射機制能夠打破封裝性,致使了java對象的屬性不安全。 idF.set(o, "110"); //set
另外,在框架滿天飛的時代下面,有的時候在運行程序的時候 會遇到 java.lang.IllegalAccessException: 對象
多數狀況下是在用反射機制下,訪問了私有屬性的緣故
每個動態代理類都必需要實現InvocationHandler這個接口,而且每一個代理類的實例都關聯到了一個handler,當咱們經過代理對象調用一個方法的時候,這個方法的調用就會被轉發爲由InvocationHandler這個接口的 invoke 方法來進行調用。咱們來看看InvocationHandler這個接口的惟一一個方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指代咱們所代理的那個真實對象
method: 指代的是咱們所要調用真實對象的某個方法的Method對象
args: 指代的是調用真實對象某個方法時接受的參數
Proxy這個類的做用就是用來動態建立一個代理對象的類,它提供了許多的方法,可是咱們用的最多的就是 newProxyInstance 這個方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
這個方法的做用就是獲得一個動態的代理對象,其接收三個參數,
loader:一個ClassLoader對象,定義了由哪一個ClassLoader對象來對生成的代理對象進行加載
interfaces:一個Interface對象的數組,表示的是我將要給我須要代理的對象提供一組什麼接口,若是我提供了一組接口給它,那麼這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了
h:一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪個InvocationHandler對象上
public interface Subject { void call(String content); } public class RealSubject implements Subject{ public void call(String content){ System.out.println(content); } }
public class DynamicProxy implements InvocationHandler { private Object subject; // 構造方法,給咱們要代理的真實對象賦初值 public DynamicProxy(Object subject) { this.subject = subject; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在代理真實對象前咱們能夠添加一些本身的操做 System.out.println("before call"); System.out.println("Method:" + method); // 當代理對象調用真實對象的方法時,其會自動的跳轉到代理對象關聯的handler對象的invoke方法來進行調用 method.invoke(subject, args); // 在代理真實對象後咱們也能夠添加一些本身的操做 System.out.println("after call"); return null; } }
public static void main(String[] arg){ // 咱們要代理的真實對象 Subject realSubject = new RealSubject(); // 咱們要代理哪一個真實對象,就將該對象傳進去,最後是經過該真實對象來調用其方法的 InvocationHandler handler = new DynamicProxy(realSubject); /* * 經過Proxy的newProxyInstance方法來建立咱們的代理對象,咱們來看看其三個參數 * 第一個參數 handler.getClass().getClassLoader() ,咱們這裏使用handler這個類的ClassLoader對象來加載咱們的代理對象 * 第二個參數realSubject.getClass().getInterfaces(),咱們這裏爲代理對象提供的接口是真實對象所實行的接口,表示我要代理的是該真實對象,這樣我就能調用這組接口中的方法了 * 第三個參數handler, 咱們這裏將這個代理對象關聯到了上方的 InvocationHandler 這個對象上 */ Subject subject = (Subject)Proxy.newProxyInstance(handler.getClass().getClassLoader(), realSubject .getClass().getInterfaces(), handler); System.out.println(subject.getClass().getName()); subject.call("test"); }
輸出:
com.sun.proxy.$Proxy0 before call Method:public abstract void refelection.proxy.Subject.call(java.lang.String) test after call