反射的基本概述 一個class文件被載入到記憶體的時候,JVM就會經行解剖,把這個class文件的所有成員全部解剖出來,然後JVM會創建一個Class對象,把這些成員信息全部都封裝起來,所謂反射就是指:我們獲取到這個Class對象,就相當於獲取到了該類的所有成員信息,我們就能操又該類的所有成員. Ja ...
-
反射的基本概述
- 一個class文件被載入到記憶體的時候,JVM就會經行解剖,把這個class文件的所有成員全部解剖出來,然後JVM會創建一個Class對象,把這些成員信息全部都封裝起來,所謂反射就是指:我們獲取到這個Class對象,就相當於獲取到了該類的所有成員信息,我們就能操又該類的所有成員.
- Java反射機制是在運行狀態中,對於任意一個類,都能夠知道這類的所有屬性和方法;
- 對於任意一個對象,都能夠調用它的任意一個方法和屬性;
- 這種動態獲取的細心以及動態調用它的任意一個方法和屬性;
- 這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制.
- 要想解剖一個類,必須要獲取到該類的位元組碼文件對象.
-
獲取Class對象的三種方式
-
通過Class.forName()方法獲取:
-
通過Class.forName()方法獲取:
static Class<?>
|
返回與帶有給定字元串名的類或介面相關聯的 Class 對象。 className--完整類名,eg:com.test.Test01 |
-
通過類名直接獲取Class對象:
eg: Class clazz=Person.class;
-
通過對象獲取Class對象
eg:Class clazz=new Person().getClass();
-
寫程式的階段
- 三種方式
Object類的getClass(類的完整類名)方法 |
讀取配置文件,判斷兩個對象是否是同一個位元組碼文件 |
靜態屬性class(鎖對象) |
當作靜態方法的鎖對象 |
Class類中靜態方法forName() |
讀取配置文件, 判斷是否是同一個位元組碼對象 |
- 代碼案例
-
1 package com.heima.reflect; 2 import com.heima.bean.Person; 3 4 public class Demo1_Reflect { 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 23 }
- 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
-
成員方法
-
成員方法
創建此 Class 對象所表示的類的一個新實例。 |
|
getConstructor(Class<?>... parameterTypes) 返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構造方法。 |
|
Constructor<?>[] |
返回一個包含某些 Constructor 對象的數組,這些對象反映此 Class 對象所表示的類的所有公共構造方法。 |
getDeclaredConstructor(Class<?>... parameterTypes) 返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或介面的指定構造方法。 |
|
Constructor<?>[] |
返回 Constructor 對象的一個數組,這些對象反映此 Class 對象表示的類聲明的所有構造方法。 |
-
創建對象_代碼示例
-
通過反射獲取成員變數_Field
-
成員方法
- Class類
-
成員方法
返回一個 Field 對象,它反映此 Class 對象所表示的類或介面的指定公共成員欄位。 |
|
Field[] |
返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或介面的所有可訪問公共欄位。 |
getDeclaredField(String name) 返回一個 Field 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明欄位。 |
|
Field[] |
返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或介面所聲明的所有欄位。 |
-
Field類
void |
setAccessible(boolean flag) 將此對象的 accessible 標誌設置為指示的布爾值。 |
void |
將指定對象變數上此 Field 對象表示的欄位設置為指定的新值。 |
-
調用方法_代碼示例
-
通過反射獲取成員方法_Method
-
Class類
-
Class類
getMethod(String name, Class<?>... parameterTypes) 返回一個 Method 對象,它反映此 Class 對象所表示的類或介面的指定公共成員方法。 |
|
Method[] |
返回一個包含某些 Method 對象的數組,這些對象反映此 Class 對象所表示的類或介面(包括那些由該類或介面聲明的以及從超類和超介面繼承的那些的類或介面)的公共 member 方法。 |
getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一個 Method 對象,該對象反映此 Class 對象所表示的類或介面的指定已聲明方法。 |
|
Method[] |
返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或介面聲明的所有方法,包括公共、保護、預設(包)訪問和私有方法,但不包括繼承的方法。 |
-
Method類
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類
-
proxy類
static Object |
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 返回一個指定介面的代理類實例,該介面可以將方法調用指派到指定的調用處理程式。 |
- 實現InvocationHandler介面重寫invoke方法
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 } 14 15 } User.java_代碼示例 1 package com.heima.動態代理; 2 3 public interface User { 4 public void add(); 5 6 public void delete(); 7 } 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 19 }
-
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 }