[TOC]
## **一、反射類的概念及作用**
### **1.什么是反射類**
動態獲取類或者對象的信息(屬性和方法),以及動態操作對象的屬性和方法的類,動態分析和使用類的信息的類
**注**:動態是指在java運行狀態
### **2.反射類的作用**
* 動態獲取:動態獲取類或對象的屬性和方法
* 動態調用:動態調用對象的屬性和方法
### **3.反射的使用場景**
* 操作因訪問權限限制的屬性和方法;
* 實現自定義注解;
* 動態加載第三方jar包
* 按需加載類,節省編譯和初始化時間;
<br>
<br>
## **二、反射技術的使用**
### **1.反射主要涉及的類**
:-: 
反射技術的核心技術是Class對象,每個類在定義以后都有各自的Class對象
<br>
| 類名 | 用途 |
| --- | --- |
| Class類 | 代表類的實體,在運行的Java應用程序中表示類和接口 |
| Field類 | 代表類的成員變量(成員變量也稱為類的屬性) |
| Method類 | 代表類的方法 |
| Constructor類 | 代表類的構造方法 |
<br>
<br>
### **2.Class類**
[Class](https://developer.android.google.cn/reference/java/lang/Class)代表類的實體,在運行的Java應用程序中表示類和接口。在這個類中提供了很多有用的方法,這里對他們簡單的分類介紹。
* **獲得類相關的方法**
| 方法 | 用途 |
| --- | --- |
| asSubclass(Class clazz) | 把傳遞的類的對象轉換成代表其子類的對象 |
| Cast | 把對象轉換成代表類或是接口的對象 |
| getClassLoader() | 獲得類的加載器 |
| getClasses() | 返回一個數組,數組中包含該類中所有公共類和接口類的對象 |
| getDeclaredClasses() | 返回一個數組,數組中包含該類中所有類和接口類的對象 |
| forName(String className) | 根據類名返回類的對象 |
| getName() | 獲得類的完整路徑名字 |
| newInstance() | 創建類的實例 |
| getPackage() | 獲得類的包 |
| getSimpleName() | 獲得類的名字 |
| getSuperclass() | 獲得當前類繼承的父類的名字 |
| getInterfaces() | 獲得當前類實現的類或是接口 |
* **獲得類中屬性相關的方法**
| 方法 | 用途 |
| --- | --- |
| getField(String name) | 獲得某個公有的屬性對象 |
| getFields() | 獲得所有公有的屬性對象 |
| getDeclaredField(String name) | 獲得某個屬性對象 |
| getDeclaredFields() | 獲得所有屬性對象 |
* **獲得類中注解相關的方法**
| 方法 | 用途 |
| --- | --- |
| getAnnotation(Class annotationClass) | 返回該類中與參數類型匹配的公有注解對象 |
| getAnnotations() | 返回該類所有的公有注解對象 |
| getDeclaredAnnotation(Class annotationClass) | 返回該類中與參數類型匹配的所有注解對象 |
| getDeclaredAnnotations() | 返回該類所有的注解對象 |
* **獲得類中構造器相關的方法**
| 方法 | 用途 |
| --- | --- |
| getConstructor(Class... parameterTypes) | 獲得該類中與參數類型匹配的公有構造方法 |
| getConstructors() | 獲得該類的所有公有構造方法 |
| getDeclaredConstructor(Class... parameterTypes) | 獲得該類中與參數類型匹配的構造方法 |
| getDeclaredConstructors() | 獲得該類所有構造方法 |
* **獲得類中方法相關的方法**
| 方法 | 用途 |
| --- | --- |
| getMethod(String name, Class... parameterTypes) | 獲得該類某個公有的方法 |
| getMethods() | 獲得該類所有公有的方法 |
| getDeclaredMethod(String name, Class... parameterTypes) | 獲得該類某個方法 |
| getDeclaredMethods() | 獲得該類所有方法 |
* **類中其他重要的方法**
| 方法 | 用途 |
| --- | --- |
| isAnnotation() | 如果是注解類型則返回true |
| isAnnotationPresent(Class annotationClass) | 如果是指定類型注解類型則返回true |
| isAnonymousClass() | 如果是匿名類則返回true |
| isArray() | 如果是一個數組類則返回true |
| isEnum() | 如果是枚舉類則返回true |
| isInstance(Object obj) | 如果obj是該類的實例則返回true |
| isInterface() | 如果是接口類則返回true |
| isLocalClass() | 如果是局部類則返回true |
| isMemberClass() | 如果是內部類則返回true |
### **3.Field類**
[Field](https://developer.android.google.cn/reference/java/lang/reflect/Field)代表類的成員變量(成員變量也稱為類的屬性)。
| 方法 | 用途 |
| --- | --- |
| equals(Object obj) | 屬性與obj相等則返回true |
| get(Object obj) | 獲得obj中對應的屬性值 |
| set(Object obj, Object value) | 設置obj中對應屬性值 |
### **4.Method類**
[Method](https://developer.android.google.cn/reference/java/lang/reflect/Method)代表類的方法。
| 方法 | 用途 |
| --- | --- |
| invoke(Object obj, Object... args) | 傳遞object對象及參數調用該對象對應的方法 |
### **5.Constructor類**
[Constructor](https://developer.android.google.cn/reference/java/lang/reflect/Constructor)代表類的構造方法。
| 方法 | 用途 |
| --- | --- |
| newInstance(Object... initargs) | 根據傳遞的參數創建類的對象 |
<br>
### **6.反射技術主要框架**
:-: 
<br>
<br>
## **三、反射操作示例**
### 3.1:反射小案例
~~~
首先我創建個Student.java的類,里面有三個屬性(name,age,credit),看代碼:
~~~
```
package day06;
public class Stundet {
// private在同一類內可見。使用對象:變量、方法。 注意:不能修飾類(外部類)
private String name;
private int age;
private boolean credit;
public String getName(){
return name;
}
public void SetName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void SetAge(int age){
this.age = age;
}
public boolean getcredit(){
return credit;
}
public void SetCreadit(boolean credit){
this.credit = credit;
}
public Stundet(String name,int age,boolean credit){
super();//調用父類中的某一個構造函數(應該為構造函數中的第一條語句)。
this.name = name; // this 是一個指向本對象的指針
this.age = age;
this.credit = credit;
}
public Stundet(){
}
}
```
<br>
接下來我們要創建一個測試的類,我給他取名字叫做test1,你們可以根據自己來創建這個類哦。
我們需要認識三中獲取類的方式:
* 類名.class
* Class.ForName 注:這個是一個方法,我們需要往里面傳遞參數,具體傳入什么參數我接下來會說的呢,
* 對象.getclass
當我們創建好了測試的類后,我們這里講解的是反射,我們當然要通過反射的方式來加載到JVM,這里就需要我上面說的Class.forName的方式來加載,這個方法是返回的一個Class對象。
<br>
```
package day06;
public class test1 {
public static void main(String args[]) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
Class studentClass = Class.forName("day06.Stundet"); //加載類,通過Class類型接受
System.out.println(studentClass);
Stundet student = (Stundet)studentClass.newInstance(); //實際是使用的無參構造實例化對象
student.SetAge(16); //使用類中的方法
System.out.println(student.getAge()); //輸出值,驗證是否成功復制
}
}
```
**運行結果:**
class day06.Stundet
16
<br>
**文件結構圖**

<br>
<br>
### 3.2:分別通過該類的有參構造和無參構造來實例化對象
? 類已經加載到了內存中了,我們是不是應該創建個Student的對象呢,我們都知道在平時普通的new一個對象的時候,其實默認是調用了該類的構造方法,那么這里也是如此我們也需要拿到該類的構造方法,這小結我們要需要如何獲取類的構造方法:
* 新增需要知識:獲取構造方法
* 使用的方法:getConstructor() 和 newInstance()
我們看下如何通過無參的構造來實例化對象,這里我們只需要使用Class的對象點出newInstance()即可,這樣系統就會實例化一個對象。
問:我調用了newInstance(),是如何實例化對象的呢?上面說要通過構造函數,我也沒有指定構造函數呀。
答:使用次方法系統會自動尋找類中的無參的構造方法,通過無參的構造來實例化對象。這里大家可以測試下,當你刪除類中的無參構造時,你再次運行代碼會出現錯誤。
```
public static String stu() throws IllegalAccessException, InstantiationException, ClassNotFoundException {
Class StuClass = Class.forName("day06.Stundet");// 加載類
Stundet sutden = (Stundet)StuClass.newInstance(); // 實際是使用的無參構造函數實例化對象
sutden.SetAge(19); // 使用類中方法
System.out.println(sutden.getAge()); // 輸出值,驗證是否成功賦值
System.out.println("執行完成");
return null;
}
```
**運行結果:**
19
執行完成
<br>
### 3.2:使用有參數的構造來實例化對象
首先我們要先拿到帶有參數的構造方法,在我上面寫的方法列表內有相關的方法,我們這里使用的是**getConstructor()** 來獲取帶參的構造,先來了解下代碼:
```
Constructor constructor =studentClass.getConstructor(String.class,int.class,boolean.class);
Student student = (Student) constructor.newInstance("Candy",20,true);
System.out.println(student.getAge());
```
這里大家看下的,在getConstructor()如果括號額你填的空則是使用的是空參數構造方法,填寫參數的意思是因為我們每個類中可能會存在大量重名的方法,比如我們使用的方法重載,這里可以通過參數列表來區分使用的是哪一個方法。當你傳入了參數的時候,在你使用newInstance時候你會發現代碼有提示說讓您傳入參數,這里的參數就是你平時實例化對象時的實際參數。
<br>
<br>
### **3.4:如何通過反射來使用類中的方法**
? 我們這里可以通過參考上面通過有參數的構造來實例化對象的代碼來處理使用類中的方法,其實這里的思路是一樣的。遵循三個步驟(這里對于我來說的是那個步驟)1.拿到類中的方法(Look,反射屌不屌)2.給方法傳遞參數,3.測試是否成功。這里的獲取方法的方法是需要傳入兩個參數
參數一:你需要的方法的名稱
參數二:方法參數的類型,有多少寫多少,反正代碼里面接受的是三個點可編長參數。 最后使用invoke方法來進行使用方法,兩個參數:
參數一:上面咱們實例化的student。
參數二:你需要往這個方法里面傳的值
```
Method method = clzzClass.getDeclaredMethod("setAge", int.class);
method.invoke(user, 20);
System.out.println(user.getAge());
```
<br>
<br>
## **四、反射的優點及缺點**
<br>
### **1.反射的優點**
* 靈活、自由度高:不受類的訪問權限限制,想對類做啥就做啥
<br>
<br>
### **2.反射的缺點**
* (1)使用反射的性能較低
* (2)使用反射相對來說不安全
* (3)破壞了類的封裝性,可以通過反射獲取這個類的私有方法和屬性
- Java自動化測試
- 第一章:Java:基礎內容
- 1.1:Java:Hello Word
- 1.2:Java:熱身
- 1.3:Java:注釋
- 1.4:Java:標識符
- 1.5:Java:常量
- 1.6:Java:基本數據類型
- 1.7:Java:引用類型
- 1.8:Java:String類
- 第二章:Java:運算符
- 2.1:Java:算數運算符
- 2.2:Java:關系運算符
- 2.3:Java:邏輯運算
- 2.4:Java:賦值運算符
- 2.5;Java:三元運算符
- 2.6:Java:位運算符
- 第三章:Java:循環控制語句
- 3.1:Java:for循環
- 3.2:Java:while循環
- 3.3:Java:switch
- 3.4:Java:if else
- 3.5:Java:練習題
- 第四章:Java:函數與全局/局部變量
- 4.1:Java:局部變量
- 4.2:Java:全局變量
- 第五章:Java:方法
- 5.1:Java:初識方法
- 5.2:Java:方法調用
- 5.3:Java:方法重載
- 5.4:Java:構造方法
- 5.5:Java:方法的注意事項
- 第六章:Java:面向對象
- 6.1:Java:小案例
- 6.2:Java:this 關鍵字
- 6.3:Java:super 關鍵字
- 6.4:Java:static 關鍵字
- 6.5:Java:final關鍵字
- 6.6:Java:instanceof 運算符
- 6.7:Java:面向對象之封裝
- 6.8:Java:面向對象之繼承
- 6.9:Java:面向對象之多態
- 第七章:Java:面向對象高級進階
- 7.1:Java:抽象類
- 7.2:Java:Java中String類
- 7.3:Java:interface接口
- 7.4:Java:ArrayList
- 7.5:Java:HashSet
- 7.6:Java:HashMap
- 7.7:Java:反射(reflection)
- 第八章:Java:日志以及異常捕獲
- 8.1:Java:log4j
- 8.2:Java:異常初識基礎
- 8.3:Java:未被捕獲的異常
- 8.4:Java:try和catch的使用
- 8.5:Java:多重catch語句的使用
- 8.6:Java:throws/throw 關鍵字
- 8.7:Java:finally關鍵字
- 8.8:Java:自定義異常
- 第九章:Java:xml and IO
- 9.1:Java:IO基本概念
- 9.2:java:properties
- 9.3:Java:xml基本介紹
- 9.4:Java:xml操作實例
- 第十章:Java:JDBC編程
- 10.1:Java:JDBC介紹
- 10.2:Java:JDBC查詢
- 10.3:Java:JDBC插入
- 10.4:Java:Batch
- 10.5:Java:JDBC連接池
- 第十一章:Java:TestNG
- 11.1:java:TestNG簡介
- 11.2:Java:TestNG小實例
- 11.3:Java:TestNG.xml文件配置
- 11.4:Java:TestNG基本注解
- 11.5:Java:TestNG注解代碼
- 11.6:Java:TestNG預期異常
- 11.7:Java:TestNG忽略測試
- 11.8:Java:TestNG超時測試
- 11.9:Java:TestNG分組測試