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
閱讀更多 異現場調查科 的文章