1. 程式人生 > 實用技巧 >Java反射機制初步理解

Java反射機制初步理解

一、反射的概念

Java的反射(reflection)機制是指在程式的執行狀態中,可以構造任意一個類的物件,可以瞭解任意一個物件所屬的類,可以瞭解任意一個類的成員變數和方法,可以呼叫任意一個物件的屬性和方法。這種動態獲取程式資訊以及動態呼叫物件的功能稱為Java語言的反射機制。反射被視為動態語言的關鍵。(百度)

說白了:就是把java類中的各種成分對映成一個個的Java物件

例如:一個類有:成員變數、方法、構造方法、包等等資訊,利用反射技術可以對一個類進行解剖,把個個組成部分對映成一個個物件。 (其實:一個類中這些成員方法、構造方法、在加入類中都有一個類來描述)

二、前提

獲取位元組碼檔案 **.Class

三種方式:

2.1、任意類繼承的Object類,自帶的getClass 方法

2.2、Class類的靜態forName(String ClassName)方法

2.3、Java中任意物件都自帶靜態的.class屬性

三、反射的幾點應用:

我首先寫一個普通的userInfo實體類,自定義一個註解myAnnotation,進行以下演示

useInfo類



 1 package Reflection;
 2 
 3 /**
 4  * className UserInfo
 5  *  測試的userInfo類
 6  *  提供私有屬性和公開屬性,構造方法全部私有,
 7  *  切記:利用反射原理,一定要將無參構造完善,後面會解釋(自動填充物件)
8 * @author Java DaKun 9 * @date 2020/8/28 10 * @version:1.0 11 * @since:jdk:1.8 12 */ 13 @MyAnnotation(id = 1,name = "tom",age = 20)//可以手動給與引數,如果不加上,會自動加上為預設值 14 public class UserInfo { 15 16 private String name = "admin"; 17 18 public String str = "你好"; 19 20 private Integer id; 21 22 @Override
23 public String toString() { 24 return "UserInfo{" + 25 "name='" + name + '\'' + 26 ", str='" + str + '\'' + 27 ", id=" + id + 28 '}'; 29 } 30 31 //公開屬性,可以加上get、set方法,私有屬性就不加了 32 33 34 public Integer getId() { 35 return id; 36 } 37 38 public void setId(Integer id) { 39 this.id = id; 40 } 41 42 //兩個帶參方法 43 private String test(String str, Integer num) { 44 System.out.println("test.......num:" + num); 45 return str; 46 } 47 @MyAnnotation(id=1)//其它不賦值,採用預設值 name() default "Jim"; age() default 18; 48 public String test(Integer num) { 49 System.out.println("num:" + num); 50 return str; 51 } 52 53 public UserInfo() { //此處應該私有,為做比較,換為public 54 } 55 56 //構造私有 57 private UserInfo(Integer id) { 58 this.id = id; 59 } 60 61 }

myannotation類

 1 package Reflection;
 2 
 3 import java.lang.annotation.*;
 4 
 5 /**
 6  * className MyAnnotation
 7  * 自定義註解
 8  * @author Java DaKun
 9  * @date 2020/8/28
10  * @version:1.0
11  * @since:jdk:1.8
12  */
13 @Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})// 自定義註解 放置位置,不太理解的同學,可以看我上一篇部落格
14 @Retention(RetentionPolicy.RUNTIME)
15 public @interface MyAnnotation {
16     int id();
17 
18     //利用反射獲取註解,主要作用就是獲取註解的引數,所以這邊給出預設賦值
19     String name() default "Jim";
20 
21     byte age() default 18;
22 }

test類

1 public class reflectionTest {
2     public static void main(String[] args) {
3         //testFiled();
4        //testMethod();
5        //testConstructor();
6       //testAnnotation();
7 
8     }

3.1、獲取構造方法

 1  private static void testConstructor() {
 2         // 通過Class物件可以獲取某個類中的:構造方法、成員變數、成員方法;並訪問成員;
 3         // *
 4         // * 1.獲取構造方法:
 5         // *        1).批量的方法:
 6         // *           public Constructor[] getConstructors():所有”公有的”構造方法
 7         //            public Constructor[] getDeclaredConstructors():獲取所有的構造方法(包括私有、受保護、預設、公有)
 8         //
 9         // *         2).獲取單個的方法,並呼叫:
10         // *             public Constructor getConstructor(Class… parameterTypes):獲取單個的”公有的”構造方法:
11         // *          public Constructor getDeclaredConstructor(Class… parameterTypes):獲取”某個構造方法”可以是私有的,或受保護、預設、公有;
12         // *
13         // *            呼叫構造方法:
14         // *             Constructor–>newInstance(Object… args)
15         Class<UserInfo> userInfoClass = UserInfo.class;
16 
17         System.out.println();
18 
19         System.out.println("--獲取無參構造-返回值陣列-");
20         Constructor<?>[] constructors = userInfoClass.getConstructors();
21         for (Constructor<?> constructor : constructors) {
22             System.out.println(constructor);
23         }
24 
25         System.out.println("--獲取任意有參構造方法- 返回值單一方法 -");
26         try {
27             
28             Constructor<?> constructor = userInfoClass.getDeclaredConstructor(Integer.class);//此處指定帶一個Integer引數的構造
29             constructor.setAccessible(true);//此有參構造私有,授權
30             UserInfo userInfo = (UserInfo) constructor.newInstance(100);
31             System.out.println(userInfo.str);//new出物件後,得到例項變數str="你好"
32 
33         } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
34             e.printStackTrace();
35         }
36 
37     }

輸出結果

1 --獲取無參構造-返回值陣列-
2 public Reflection.UserInfo()
3 --獲取任意有參構造方法- 返回值單一方法 -
4 你好

3.2、獲取成員變數

 1  /*拿到類屬性*/
 2     /* 1.批量的
 3      *       1).Field[] getFields():獲取所有的”公有欄位”
 4      *       2).Field[] getDeclaredFields():獲取所有欄位,包括:私有、受保護、預設、公有;
 5      * 2.獲取單個的:
 6      *      1).public Field getField(String fieldName):獲取某個”公有的”欄位;
 7      *         2).public Field getDeclaredField(String fieldName):獲取某個欄位(可以是私有的)
 8      *
 9      *   設定欄位的值:
10      *        Field –> public void set(Object obj,Object value):
11      *                  引數說明:
12      *                   1.UserInfoClass:要設定的欄位所在的物件;
13      *                  2.name:要為欄位設定的值;*/
14     private static void testFiled() {
15 
16         // 等於Class UserInfoClass1 = UserInfo.class; ?其實就是UserInfo自己或者子類,主要用於安全地訪問資料
17         Class<? extends UserInfo> UserInfoClass = UserInfo.class;
18 
19         System.out.println("--獲取所有公有屬性-返回值陣列-");
20         Field[] Fields = UserInfoClass.getFields();
21         for (Field Field : Fields) {
22 
23             System.out.println(Field);
24         }
25 
26         System.out.println("--獲取所有屬性,包括私有的-返回值陣列-");
27         Field[] declaredFields = UserInfoClass.getDeclaredFields();
28         for (Field declaredField : declaredFields) {
29             System.out.println(declaredField);
30         }
31 
32         System.out.println("--獲取任一公有屬性-返回值單一屬性-");
33         try {
34             Field field = UserInfoClass.getDeclaredField("id");
35             System.out.println(field.getName());
36             System.out.println(field.getType());
37         } catch (NoSuchFieldException e) {
38             e.printStackTrace();
39         }
40 
41         System.out.println("--獲取任意屬性,包括私有的-返回值單一屬性-");
42         try {
43             Field field = UserInfoClass.getDeclaredField("name");
44             System.out.println(field.getName());
45             System.out.println(field.getType());
46             field.setAccessible(true);//由於name屬性是私有的,需要授權
47         } catch (NoSuchFieldException e) {
48             e.printStackTrace();
49         }
50 
51         
52     }

輸出結果

 1 --獲取所有公有屬性-返回值陣列-
 2 public java.lang.String Reflection.UserInfo.str
 3 --獲取所有屬性,包括私有的-返回值陣列-
 4 private java.lang.String Reflection.UserInfo.name
 5 public java.lang.String Reflection.UserInfo.str
 6 private java.lang.Integer Reflection.UserInfo.id
 7 --獲取任一公有屬性-返回值單一屬性-
 8 id
 9 class java.lang.Integer
10 --獲取任意屬性,包括私有的-返回值單一屬性-
11 name
12 class java.lang.String

3.3、獲取成員方法

 1     private static void testMethod() {
 2         // * 獲取成員方法並呼叫:
 3         // *
 4         // * 1.批量的:
 5         // *         public Method[] getMethods():獲取所有”公有方法”;(包含了父類的方法也包含Object類)
 6         // *        public Method[] getDeclaredMethods():獲取所有的成員方法,包括私有的(不包括繼承的)
 7         // * 2.獲取單個的:
 8         // *       public Method getMethod(String name,Class<?>… parameterTypes):
 9         // *                  引數:
10         // *                         name : 方法名;
11         // *                         Class … : 形參的Class型別物件
12         // *        public Method getDeclaredMethod(String name,Class<?>… parameterTypes)
13         // *
14         // *   呼叫方法:
15         // *      Method –> public Object invoke(Object obj,Object… args):
16         // *                  引數說明:
17         // *                   obj : 要呼叫方法的物件;
18         // *                     args:呼叫方式時所傳遞的實參;
19         Class<UserInfo> userInfoClass = UserInfo.class;
20 
21 
22         System.out.println("--獲取所有公有方法包括父類、Object等-返回值陣列-");
23         Method[] methods = userInfoClass.getMethods();
24         for (Method method : methods) {
25             System.out.println(method);
26         }
27 
28         System.out.println("--獲取類所有方法,包括私有的-返回值陣列-");
29         Field[] declaredFields = userInfoClass.getDeclaredFields();
30         for (Field declaredField : declaredFields) {
31             System.out.println(declaredField);
32         }
33 
34         System.out.println("--獲取任意公有方法-返回值  單一方法-");
35         try {
36             Method test = userInfoClass.getMethod("test", Integer.class); //指定一個引數的方法(此方法為public修飾),此方法返回值為例項變數str
37             UserInfo userInfo = userInfoClass.newInstance(); //獲取一個例項
38             Object test1 = test.invoke(userInfo, 100); // 例項 + 引數
39             System.out.println(test1);
40 
41         } catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
42             e.printStackTrace();
43         }
44 
45         System.out.println("---獲取任意方法,包括私有的-返回值  單一方法----");
46         try {
47             Method test = userInfoClass.getDeclaredMethod("test", String.class, Integer.class);//可以指定私有test方法
48             UserInfo userInfo = userInfoClass.newInstance(); //獲取一個例項
49             test.setAccessible(true); //授權
50             Object hello = test.invoke(userInfo, "hello", 100);
51             System.out.println(hello);
52         } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) {
53             e.printStackTrace();
54         }
55 
56 
57     }

輸出值為

 1 Reflection.reflectionTest
 2 --獲取所有公有方法-返回值陣列-
 3 public java.lang.String Reflection.UserInfo.toString()
 4 public java.lang.Integer Reflection.UserInfo.getId()
 5 public java.lang.String Reflection.UserInfo.test(java.lang.Integer)
 6 public void Reflection.UserInfo.setId(java.lang.Integer)
 7 public final void java.lang.Object.wait() throws java.lang.InterruptedException
 8 public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
 9 public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
10 public boolean java.lang.Object.equals(java.lang.Object)
11 public native int java.lang.Object.hashCode()
12 public final native java.lang.Class java.lang.Object.getClass()
13 public final native void java.lang.Object.notify()
14 public final native void java.lang.Object.notifyAll()
15 --獲取所有方法,包括私有的-返回值陣列-
16 private java.lang.String Reflection.UserInfo.name
17 public java.lang.String Reflection.UserInfo.str
18 private java.lang.Integer Reflection.UserInfo.id
19 --獲取任意公有方法-返回值  單一方法-
20 num:100
21 你好
22 ---獲取任意公有方法,包括私有的-返回值  單一方法----
23 test.......num:100
24 hello

3.4、獲取註解

 1    private static void testAnnotation() {
 2         Class<UserInfo> infoClass = UserInfo.class;
 3 
 4         //獲得類上的註解
 5         MyAnnotation annotation = infoClass.getAnnotation(MyAnnotation.class);
 6         System.out.println(annotation.name());//賦值了tom
 7 
 8 
 9         System.out.println("-------------------------------");
10         try {
11             //獲得方法上的註解
12             MyAnnotation myAnnotation = infoClass.getMethod("test", Integer.class).getAnnotation(MyAnnotation.class);
13             System.out.println(myAnnotation.name());//不賦值為Jim
14         } catch (NoSuchMethodException e) {
15             e.printStackTrace();
16         }
17     }

輸出結果

1 tom
2 -------------------------------
3 Jim