反射,動態代理隨筆
反射的基本概述
- 一個class文件被加載到內存的時候,JVM就會經行解剖,把這個class文件的所有成員全部解剖出來,然後JVM會創建一個Class對象,把這些成員信息全部都封裝起來,所謂反射就是指:我們獲取到這個Class對象,就相當於獲取到了該類的所有成員信息,我們就能操又該類的所有成員.
- Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這類的所有屬性和方法;
- 對於任意一個對象,都能夠調用它的任意一個方法和屬性;
- 這種動態獲取的細心以及動態調用它的任意一個方法和屬性;
- 這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制.
- 要想解剖一個類,必須要獲取到該類的字節碼文件對象.
獲取Class對象的三種方式
- 通過Class.forName()方法獲取:
static Class<?>
| forName(String className) 返回與帶有給定字符串名的類或接口相關聯的 Class 對象。 className--完整類名,eg:com.test.Test01 |
- 通過類名直接獲取Class對象:
eg: Class clazz=Person.class;
- 通過對象獲取Class對象:
eg:Class clazz=new Person().getClass();
- 寫程序的階段
- 三種方式
Object | 讀取配置文件,判斷兩個對象是否是同一個字節碼文件 |
靜態屬性class(鎖對象) | 當作靜態方法的鎖對象 |
Class類中靜態方法forName() | 讀取配置文件, 判斷是否是同一個字節碼對象 |
- 代碼案例
?
1 ? package com.heima.reflect;
2 import com.heima.bean.Person;
3
4 public class
5
6 /**
7 * @param args
8 * @throws ClassNotFoundException
9 */
10 public static void main(String[] args) throws ClassNotFoundException {
11 Class clazz1 = Class.forName("");
12 // 接口 a = 實現類的對象 a.方法
13 //方式一
14 Class clazz2 = Person.class;
15 //方式二
16 Person p = new Person();
17 Class clazz3 = p.getClass();
18 //方式三
19 System.out.println(clazz1 == clazz2);
20 System.out.println(clazz2 == clazz3);
21 }
22
- }
- Class.forName()讀取配置文件_代碼示例
1 ?package com.heima.reflect;
2
3 import java.io.BufferedReader;
4 import java.io.FileReader;
5
6 public class Demo2_Reflect {
7
8 /**
9 * * 榨汁機(Juicer)榨汁的案例
10 * 分別有水果(Fruit)蘋果(Apple)香蕉(Banana)桔子(Orange)榨汁(squeeze)
11 * @throws IOException
12 */
13 public static void main(String[] args) throws Exception {
14 Juicer j = new Juicer(); //創建榨汁機
15 //j.run(new Apple());
16 //j.run(new Orange());
17 BufferedReader br = new BufferedReader(new FileReader("config.properties"));//com.heima.reflect.Apple
18 Class clazz = Class.forName(br.readLine()); //獲取該類的字節碼文件
19 Fruit f = (Fruit) clazz.newInstance(); //創建實例對象
20
21 j.run(f);
22 }
23 }
24 interface Fruit {
25 public void squeeze();
26 }
27 class Apple implements Fruit {
28 public void squeeze() {
29 System.out.println("榨出一杯蘋果汁兒");
30 }
31 }
32
33 class Orange implements Fruit {
34 public void squeeze() {
35 System.out.println("榨出一杯橘子汁兒");
36 }
37 }
38
39 class Juicer {
40 /*public void run(Apple a) {
41 a.squeeze();
42 }
43
44 public void run(Orange o) {
45 o.squeeze();
46 }*/
47
48 public void run(Fruit f) {
49 f.squeeze();
50 }
51
52 }
通過反射獲取構造函數_Constructor
- 成員方法
T | newInstance() 創建此 Class 對象所表示的類的一個新實例。 |
Constructor<T> | getConstructor(Class<?>... parameterTypes) 返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構造方法。 |
Constructor<?>[] | getConstructors() 返回一個包含某些 Constructor 對象的數組,這些對象反映此 Class 對象所表示的類的所有公共構造方法。 |
Constructor<T> | getDeclaredConstructor(Class<?>... parameterTypes) 返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或接口的指定構造方法。 |
Constructor<?>[] | getDeclaredConstructors() 返回 Constructor 對象的一個數組,這些對象反映此 Class 對象表示的類聲明的所有構造方法。 |
- 創建對象_代碼示例
通過反射獲取成員變量_Field
- 成員方法
- Class類
Field | getField(String name) 返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。 |
Field[] | getFields() 返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或接口的所有可訪問公共字段。 |
Field | getDeclaredField(String name) 返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。 |
Field[] | getDeclaredFields() 返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段。 |
- Field類
void | setAccessible(boolean flag) 將此對象的 accessible 標誌設置為指示的布爾值。 |
void | set(Object obj, Object value) 將指定對象變量上此 Field 對象表示的字段設置為指定的新值。 |
- 調用方法_代碼示例
通過反射獲取成員方法_Method
- Class類
Method | getMethod(String name, Class<?>... parameterTypes) 返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。 |
Method[] | getMethods() 返回一個包含某些 Method 對象的數組,這些對象反映此 Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。 |
Method | getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。 |
Method[] | getDeclaredMethods() 返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 |
- Method類
Object | invoke(Object obj, Object... args) 對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。 |
- 案例
通過反射越過泛型檢查
- 需求:ArrayList的一個對象,在這個集合中添加一個字符串數據,如何實現呢?
- 泛型只在編譯期有效,在運行期會被擦除掉.
- 代碼示例
1 ?package com.heima.test;
2
3 import java.lang.reflect.Method;
4 import java.util.ArrayList;
5
6 public class Test1 {
7
8 /**
9 * @param args
10 * ArrayList<Integer>的一個對象,在這個集合中添加一個字符串數據,如何實現呢?
11 * 泛型只在編譯期有效,在運行期會被擦除掉
12 * @throws Exception
13 */
14 public static void main(String[] args) throws Exception {
15 ArrayList<Integer> list = new ArrayList<>();
16 list.add(111);
17 list.add(222);
18
19 Class clazz = Class.forName("java.util.ArrayList"); //獲取字節碼對象
20 Method m = clazz.getMethod("add", Object.class); //獲取add方法
21 m.invoke(list, "abc");
22
23 System.out.println(list);
24
25 }
26
27 }
動態代理的概述和實現
- 動態代理:在程序運行過程中產生的這個對象,而程序運行過程中產生對象其實就是我們剛才反射講解的內容,所以,動態代理其實就是通過反射來生成一個代理
- 在Java中java.lang.reflect包下提供了一個Proxy類和一個InvocationHandler接口,通過使用這個類和接口就可以生成動態代理對象。JDK提供的代理只能針對接口做代理。我們有更強大的代理cglib,Proxy類中的方法創建動態代理類對象.
- 成員方法
- proxy類
static Object | newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一個指定接口的代理類實例,該接口可以將方法調用指派到指定的調用處理程序。 |
- 實現InvocationHandler接口重寫invoke方法
Object | invoke(Object proxy, Method method, Object[] args) 在代理實例上處理方法調用並返回結果。 |
- 代碼案例
- MyInvocationHandler.java_代碼示例
1 ?package com.heima.動態代理;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.Method;
5
6 public class MyInvocationHandler implements InvocationHandler {
7 private Object target;
8
9 public MyInvocationHandler(Object target) {
10 this.target = target;
11 }
12 @Override
13 public Object invoke(Object proxy, Method method, Object[] args)
14 throws Throwable {
15 System.out.println("權限校驗");
16 method.invoke(target, args); //執行被代理target對象的方法
17 System.out.println("日誌記錄");
18 return null;
19 }
20
21 }
- Student.java_代碼示例
1 ?package com.heima.動態代理;
2
3 public interface Student {
4 public void login();
5
6 public void submit();
7 }
- StudentImp.java_代碼示例
1 ?package com.heima.動態代理;
2
3 public class StudentImp implements Student {
4
5 @Override
6 public void login() {
7 System.out.println("登錄");
8 }
9
10 @Override
11 public void submit() {
12 System.out.println("提交");
13 }
- User.java_代碼示例
1 ?package com.heima.動態代理;
2
3 public interface User {
4 public void add();
5
6 public void delete();
- }
- UserImp.java_代碼示例
1 ?package com.heima.動態代理;
2
3 public class UserImp implements User {
4
5 @Override
6 public void add() {
7 //System.out.println("權限校驗");
8 System.out.println("添加功能");
9 //System.out.println("日誌記錄");
10 }
11
12 @Override
13 public void delete() {
14 //System.out.println("權限校驗");
15 System.out.println("刪除功能");
16 //System.out.println("日誌記錄");
17 }
18
- Test.java_代碼示例
1 ?package com.heima.動態代理;
2
3 import java.lang.reflect.Proxy;
4
5 public class Test {
6
7 /**
8 * @param args
9 */
10 public static void main(String[] args) {
11 /*UserImp ui = new UserImp();
12 ui.add();
13 ui.delete();
14
15 System.out.println("-------------------------------");*/
16 /*
17 * public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,
18 * InvocationHandler h)
19 */
20 /*MyInvocationHandler m = new MyInvocationHandler(ui);
21 User u = (User)Proxy.newProxyInstance(ui.getClass().getClassLoader(), ui.getClass().getInterfaces(), m);
22 u.add();
23 u.delete();*/
24
25 StudentImp si = new StudentImp();
26 si.login();
27 si.submit();
28 System.out.println("-------------------------------");
29 MyInvocationHandler m = new MyInvocationHandler(si);
30 Student s = (Student)Proxy.newProxyInstance(si.getClass().getClassLoader(), si.getClass().getInterfaces(), m);
31
32 s.login();
33 s.submit();
34 }
35
36 }
反射,動態代理隨筆