13.Java反射機制

13.Java反射機制

1.如何創建Class的實例(重點)

1.1過程:源文件經過編譯(javac.exe)以後,得到一個或多個.class文件。.class文件經過運行(java.exe)這步,

就需要進行類的加載(通過JVM的類的加載器),記載到內存中的緩存。每一個放入緩存中的.class文件就是一個Class的實例!

1.2 Class的一個對象,對應著一個運行時類。相當於一個運行時類本身充當了Class的一個實例。

1.3 java.lang.Class是反射的源頭。 接下來涉及到反射的類都在java.lang.reflect子包下。如:Field Method Constructor Type Package..

當通過Class的實例調用getMethods() --->Method , getConstructors() ---->Constructor

1.4實例化Class的方法(三種):

// 1.調用運行時類的.class屬性

Class clazz1 = Person.class;

System.out.println(clazz1);

Class clazz2 = Creator.class;

System.out.println(clazz2);

// 2.通過運行時類的對象,調用其getClass()方法

Person p = new Person();

Class clazz3 = p.getClass();

System.out.println(clazz3);

// 3.調用Class的靜態方法forName(String className)。此方法報ClassNotFoundException

String className = "com.yxcdck.java.Person";

Class clazz4 = Class.forName(className);

System.out.println(clazz4);

2.有了Class實例以後,可以做什麼?應用一:可以創建對應的運行時類的對象(重點)

//獲取運行時類的對象:方法一

@Test

public void test1() throws Exception{

Class clazz = Class.forName("com.yxcdck.review.Animal");

Object obj = clazz.newInstance();

Animal a = (Animal)obj;

System.out.println(a);

}

//調用指定的構造器創建運行時類的對象

@Test

public void test2() throws Exception{

Class clazz = Animal.class;

Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);

cons.setAccessible(true);

Animal a = (Animal)cons.newInstance("Tom",10);

System.out.println(a);

}

3.有了Class實例以後,可以做什麼?應用二:獲取對應的運行時類的完整的類的結構:屬性、方法、構造器、包、父類、接口、泛型、註解、異常、內部類。。。

如:Method[] m1 = clazz.getMethods() :獲取到對應的運行時類中聲明的權限為public的方法(包含其父類中的聲明的public)

Method[] m2 = clazz.getDeclaredMethods():獲取到對應的運行時類中聲明的所有的方法(①任何權限修飾符修飾的都能獲取②不含父類中的)

4.有了Class實例以後,可以做什麼?應用三:調用對應的運行時類中指定的結構(某個指定的屬性、方法、構造器)(重點)

//調用指定屬性

@Test

public void test3() throws Exception{

Class clazz = Class.forName("com.yxcdck.review.Animal");

Object obj = clazz.newInstance();

Animal a = (Animal)obj;

//調用非public的屬性

Field f1 = clazz.getDeclaredField("name");

f1.setAccessible(true);

f1.set(a, "Jerry");

//調用public的屬性

Field f2 = clazz.getField("age");

f2.set(a, 9);

System.out.println(f2.get(a));

System.out.println(a);

//調用static的屬性

Field f3 = clazz.getDeclaredField("desc");

System.out.println(f3.get(null));

}

//調用指定的方法

@Test

public void test4() throws Exception{

Class clazz = Class.forName("com.yxcdck.review.Animal");

Object obj = clazz.newInstance();

Animal a = (Animal)obj;

//調用非public的方法

Method m1 = clazz.getDeclaredMethod("getAge");

m1.setAccessible(true);

int age = (Integer)m1.invoke(a);

System.out.println(age);

//調用public的方法

Method m2 = clazz.getMethod("show", String.class);

Object returnVal = m2.invoke(a,"金毛");

System.out.println(returnVal);

//調用static的方法

Method m3 = clazz.getDeclaredMethod("info");

m3.setAccessible(true);

// m3.invoke(Animal.class);

m3.invoke(null);

}

5.動態代理---反射的應用。體會反射的動態性

代理設計模式的原理:

使用一個代理將對象包裝起來, 然後用該代理對象取代原始對象. 任何對原始對象的調用都要通過代理. 代理對象決定是否以及何時

將方法調用轉到原始對象上

靜態代理:要求被代理類和代理類同時實現相應的一套接口;通過代理類的對象調用重寫接口的方法時,實際上執行的是被代理類的同樣的

方法的調用。

動態代理:在程序運行時,根據被代理類及其實現的接口,動態的創建一個代理類。當調用代理類的實現的抽象方法時,就發起對被代理類同樣

方法的調用。

涉及到的技術點:①提供一個實現了InvocationHandler接口實現類,並重寫其invoke()方法

②Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),h);

//注:obj:被代理類對象 ; h:實現了InvocationHandler接口的實現類的對象

//動態代理的使用,體會反射是動態語言的關鍵

interface Subject {

void action();

}

// 被代理類

class RealSubject implements Subject {

public void action() {

System.out.println("我是被代理類,記得要執行我哦!麼麼~~");

}

}

class MyInvocationHandler implements InvocationHandler {

Object obj;// 實現了接口的被代理類的對象的聲明

// ①給被代理的對象實例化②返回一個代理類的對象

public Object blind(Object obj) {

this.obj = obj;

return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj

.getClass().getInterfaces(), this);

}

//當通過代理類的對象發起對被重寫的方法的調用時,都會轉換為對如下的invoke方法的調用

@Override

public Object invoke(Object proxy, Method method, Object[] args)

throws Throwable {

//method方法的返回值時returnVal

Object returnVal = method.invoke(obj, args);

return returnVal;

}

}

public class TestProxy {

public static void main(String[] args) {

//1.被代理類的對象

RealSubject real = new RealSubject();

//2.創建一個實現了InvacationHandler接口的類的對象

MyInvocationHandler handler = new MyInvocationHandler();

//3.調用blind()方法,動態的返回一個同樣實現了real所在類實現的接口Subject的代理類的對象。

Object obj = handler.blind(real);

Subject sub = (Subject)obj;//此時sub就是代理類的對象

sub.action();//轉到對InvacationHandler接口的實現類的invoke()方法的調用

//再舉一例

NikeClothFactory nike = new NikeClothFactory();

ClothFactory proxyCloth = (ClothFactory)handler.blind(nike);//proxyCloth即為代理類的對象

proxyCloth.productCloth();

}

}

動態代理與AOP


分享到:


相關文章: