Java基礎(十三)反射

来源:https://www.cnblogs.com/zt19994/archive/2018/03/05/8506159.html
-Advertisement-
Play Games

一、反射 1、反射概念 JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。 要想解剖一個類,必須先要獲取到該類的位元組碼文件對象。而解剖使用的就 ...


一、反射

1、反射概念

  JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。

  要想解剖一個類,必須先要獲取到該類的位元組碼文件對象。而解剖使用的就是Class類中的方法.所以先要獲取到每一個位元組碼文件對應的Class類型的對象。

2、Java 反射機制的主要用途

1、在運行時判斷任意一個對象所屬的類。

2、在運行時構造任意一個類的對象。

3、在運行時判斷任意一個類所具有的成員變數和方法。

4、在運行時調用任意一個對象的方法。

3、三種獲取Class實例對象的方式

1、Person p = new Person();

  Class c = p.getClass();

  已知類的對象,通過 getClass() 方法獲取 Class 實例對象。

2、Class c2 = Person.class;

  任意數據類型都具備一個 class 靜態成員變數,看上去要比第一種方式簡單。

3、將類名作為字元串傳遞給Class類中的靜態方法 forName 即可。

  Class c3 = Class.forName("Person");

 1 import com.reflect.pojo.Product;
 2 import org.junit.Test;
 3 
 4 /**
 5  * @author zt1994 2018/3/5 14:25
 6  */
 7 public class TestReflect {
 8 
 9     /**
10      * 測試三種獲取Class對象的方法
11      * @throws Exception
12      */
13     @Test
14     public void testGetClass() throws Exception {
15         //實例化類的三種方法   任何對象都是Class的實例
16         //第一種 對象名.getClass()
17         Product product = new Product();
18         Class<? extends Product> aClass1 = product.getClass();
19         System.out.println(aClass1); //class com.reflect.pojo.Product
20         //第二種 類型.class
21         Class<Product> aClass2 = Product.class;
22         System.out.println(aClass2);
23         //第三種 Class 類中的靜態方法 static Class<?>  forName(String className) className是類或者介面的許可權定名
24         Class<?> aClass3 = Class.forName("com.reflect.pojo.Product"); 
25         System.out.println(aClass3);
26         //比較
27         System.out.println(aClass1==aClass2); //true
28         System.out.println(aClass1==aClass3); //true
29         System.out.println(aClass2==aClass3); //true
30     }
31 }

4、反射的作用

1、增加程式的靈活性,避免將程式寫死到代碼里(解除硬編碼的問題)

2、Java的反射機制它知道類的基本結構,可以動態的去獲取類這樣的結構的結構;

3、可以讓程式員在不知道其它程式員會有什麼類的時候就編寫完成自己的代碼;

4、反射的優點:靈活,功能強大(可以拿到私有的....)

5、反射的缺點:破壞封裝,影響性能;

5、反射運用(常用 API)

1、獲取構造方法

getConstructors  不能獲取私有的構造方法。

getDeclaredConstructors  可以獲取所有構造方法,包括私有的。

  Product類:

 1 public class Product {
 2     private Integer id;
 3     private String productName;
 4     private Integer classifyId;
 5     private String brand;
 6 
 7     public Integer getId() {
 8         return id;
 9     }
10 
11     public void setId(Integer id) {
12         this.id = id;
13     }
14 
15     public String getProductName() {
16         return productName;
17     }
18 
19     public void setProductName(String productName) {
20         this.productName = productName;
21     }
22 
23     public Integer getClassifyId() {
24         return classifyId;
25     }
26 
27     public void setClassifyId(Integer classifyId) {
28         this.classifyId = classifyId;
29     }
30     
31     public String getBrand() {
32         return brand;
33     }
34 
35     public void setBrand(String brand) {
36         this.brand = brand;
37     }
38 }

  獲取構造方法:

 1   /**
 2      * 測試獲取構造方法
 3      */
 4     @Test
 5     public void testGetConstructor() throws ClassNotFoundException {
 6         Class<?> aClass = Class.forName("com.reflect.pojo.Product");
 7         //獲取構造器
 8         Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
 9         for (Constructor<?> declaredConstructor : declaredConstructors) {
10             System.out.println("declaredConstructor: [" + declaredConstructor + "]");
11         }
12     }

2、反射創建對象

1、 newInstance()

註意  只能夠調用無參數的構造方法,無參數的構造方法必須是有許可權被訪問到的。

2、獲得構造器對象之後,通過構造器來創建對象

 1   /**
 2      * 測試反射創建對象的兩種方法
 3      */
 4     @Test
 5     public void testCreateInstance() throws Exception {
 6         //方法一  Class類中有對應的方法 newInstance()
 7         Class<?> aClass = Class.forName("com.reflect.pojo.Product");
 8         Product product = (Product) aClass.newInstance();
 9 
10         //方法二 獲得構造器對象之後,通過構造器來創建對象
11         Constructor<?> constructor = aClass.getDeclaredConstructor();
12         Product product1 = (Product) constructor.newInstance();
13     }

3、獲取方法

1、獲取所有方法

  getMethods

  getDeclaredMethods

2、獲取單個方法

  getMethod

  getDeclaredMethod

 1     /**
 2      * 測試獲取方法
 3      */
 4     @Test
 5     public void testGetMethods() throws Exception{
 6         Class<?> aClass = Class.forName("com.reflect.pojo.Product");
 7 
 8         //獲取方法
 9         Method[] declaredMethods = aClass.getDeclaredMethods();
10         for (int i = 0; i < declaredMethods.length; i++){
11             Method declaredMethod = declaredMethods[i];
12             //獲取方法返回類型
13             Class<?> returnType = declaredMethod.getReturnType();
14             //輸出方法返回類型
15             System.out.println("returnType: [" + returnType + "]");
16             //獲取方法參數類型
17             Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
18             for (Class parameterType: parameterTypes){
19                 System.out.println("parameterType: [" + parameterType + "]");
20             }
21             //輸出變數名稱
22             System.out.println("i: " + i + " declaredMethod: ["+declaredMethod.getName() + "]");
23         }
24     }

4、獲取欄位(成員變數)

1、獲取所有欄位

  getFields、getDeclaredFields

2、獲取單個欄位

  getField、getDeclaredField

3、修改獲取欄位的值

  set(Object obj,Object value); 將指定對象變數上此 Field 對象表示的欄位設置為指定的新值。

  get(Object obj);  返回指定對象(傳入的obj)上此 Field 表示的欄位的值。

 1     /**
 2      * 獲取欄位
 3      */
 4     @Test
 5     public void testAPI() throws ClassNotFoundException {
 6         //獲取field
 7         Class<?> aClass = Class.forName("com.reflect.pojo.Product");
 8         //獲取欄位
 9         Field[] declaredFields = aClass.getDeclaredFields();
10         for (Field df:declaredFields){
11             //獲取欄位類型
12             Class<?> type = df.getType();
13             System.out.println("type: [" + type + "]");
14             System.out.println(df);
15         }
16     }

5、通過反射調用方法

1、獲得類對應的Class實例;

2、通過反射得到類中的指定的方法

3、通過反射(Method類)來調用方法

Method中的方法:

Object invoke(Object obj, Object... args)

obj: 調用的對象

args: 方法參數

 1     /**
 2      * 反射調用方法
 3      */
 4     @Test
 5     public void testInvoke() throws Exception {
 6         Product product = new Product();
 7         product.setId(7);
 8         product.setClassifyId(3);
 9         product.setBrand("聯想");
10         product.setProductName("G480筆記本");
11 
12         //1.獲取位元組碼
13         Class<?> aClass = product.getClass();
14         //2.獲取屬性
15         Field[] declaredFields = aClass.getDeclaredFields();
16         //3.獲取屬性數組
17         for (Field declaredField : declaredFields) {
18             //獲取屬性名
19             String fieldName = declaredField.getName();
20             //回去get方法字元串名
21             String methodName = "get" + toMethodName(fieldName);
22             //通過方法名稱使用反射獲取方法對象
23             Method method = aClass.getMethod(methodName);
24             //執行方法
25             Object invoke = method.invoke(product);
26             //裝換字元串類型
27             String s = String.valueOf(invoke);
28             System.out.println(fieldName + "=" + s);
29         }
30     }

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 後端開發:1、高級java軟體架構師實戰培訓視頻教程2、大型SpringMVC,Mybatis,Redis,Solr,Nginx,SSM分散式電商項目視頻教程3、Spark Streaming實時流處理項目實戰4、Java校招面試 Google面試官親授5、Java開發企業級許可權管理系統6、Java ...
  • 關鍵字驅動小例子 ...
  • 這題有如下幾個點要註意: 1.最開始輸出的開始時間和截止時間,這裡是不包含截止時間的。 2.月份和星期的英文表示是大小寫任意的,並未規定必須是Sat這種形式。 3.星期天的數字標識是0。 我的思路是,首先將月份、天數、小時、分鐘、星期統統規格化,格式如下: 月份:規格化前:1,2-4 規格化後:1 ...
  • 一、發現問題 <select id="queryStudentByNum" resultType="student" parameterType="string"> select num,name,phone from student <where> <if test = " num!=null a ...
  • (一) 前言 簡單的說就是分為2層,頁面class 和測試class。 頁面class:分為父類和子類(子類指具體的頁面,每一個頁面都創建一個類),父類中定義公有的屬性和方法(操作)。 #對面向對象有瞭解的,應該很容易理解抽象出公有屬性和方法的意思 #父類和子類我是按自己的理解進行描述的,或者可以說 ...
  • 通過pycharm安裝selenium 1.配置好python和pycharm,打開pycharm,點擊左上角的File->Setting->Project Interpreter,點擊右側的添加按鈕 2.在新彈出的視窗中輸入selenium,選擇selenium,點擊左下角的install pac ...
  • #include #include #include using namespace std; const int MAX=1005; int main() { int x[MAX]={0},y[MAX]={0},z[2*MAX+1]={0}; string a,b; cin>>a>>b; reve... ...
  • 棧 1.定義:棧是限定僅在表尾進行插入或刪除操作的線性表。因此,對棧來說,表尾端有其特殊含義,稱為棧頂,相應地, 表頭端稱為棧底。不含元素的空表稱為空棧。 假設棧S=(a1,a2,a3,...,an),則稱a1為棧底元素,an為棧頂元素。棧中元素按a1,a2,a3,...,an的次序進棧,退棧的第 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...