首頁 Java Java基礎 怎麼理解java反射

怎麼理解java反射

Nov 13, 2019 am 10:19 AM
java

怎麼理解java反射

怎麼理解java反射?

概述

Java 反射是可以讓我們在執行時間取得類別的方法、屬性、父類別、介面等類別的內部資訊的機制。也就是說,反射本質上是一個「反著來」的過程。當我們透過new創建一個類別的實例時,實際上是由Java虛擬機根據這個類別的Class物件在運行時構建出來的,而反射是透過一個類別的Class物件來獲取它的定義信息,從而我們可以訪問到它的屬性、方法,知道這個類別的父類別、實作了哪些介面等資訊。

Class類別

我們知道使用javac能夠將.java檔案編譯為.class文件,這個.class檔案包含了我們對類別的原始定義資訊(父類別、介面、建構器、屬性、方法等)。 .class檔案在運行時會被ClassLoader載入到Java虛擬機器(JVM)中,當一個.class檔案被載入後,JVM會為之產生一個Class對象,我們在程式中透過new實例化的物件其實是在運行時根據對應的Class物件建構出來的。確切的說,這個Class物件其實是java.lang.Class泛型類別的一個實例,例如Class物件就是為一個封裝了MyClass類別的定義資訊的Class實例。由於java.lang.Class類別不存在公有建構器,因此我們不能直接實例化這個類,我們可以透過以下方法取得一個Class物件。

在下面的講解中,我們將以People類別和Student類別為例:

public class People {
      private String name;
      private int age;
      public People(String name, int age) {
          this.name = name;
              this.age = age;
      }
      public int getAge() {
          return age;
      } 
      public String getName() {
          return name;
      } 
      public void setAge(int age) {
          this.age = age;
      } 
      public void setName(String name) {
          this.name = name;
      }
      public void speak() {
        System.out.println(getName() + " " + getAge());
     }
}
 
public class Student extends People {
  private int grade;
  public Student(String name, int age) {    
    super(name, age);  
  }
  public Student(String name, int age, int grade) {
    super(name, age);            
    this.grade = grade;  
  }      
  public int getGrade() {   
    return grade;  
  }     
  public void setGrade(int grade) {   
    this.grade = grade;  
  }    
  private void learn(String course) {    
    System.out.println(name + " learn " + course);  
  }
}
登入後複製

透過類別名稱取得Class物件

若在編譯期間知道一個類別的名字,我們可以這樣取得它的Class物件:

Class<People> peopleClass = People.class;
登入後複製

還有一種根據類別的完整路徑名取得Class物件的方法如下所示:

//假设People类在com.test包中
Class<People> peopleClass = Class.forName("com.test.People");
登入後複製

注意,Class.forName()方法的參數必須是一個類別的全路徑名。實際上,只要我們「import com.test.People",就可以直接透過」People.class"取得他的Class對象,而不用寫出全路徑這麼麻煩。 (若在呼叫Class.forName()方法時,沒有在classpath找到對應的類,會拋出ClassNotFoundException。)

透過物件本身取得其Class物件

People people = new People("Bill", 18);
Class<People> peopleClass = people.getClass();
登入後複製

透過反射取得類的建構器

一旦我們取得了People的Class 對象,我們便可以透過這個Class 物件取得到People類別的原始定義資訊。首先,我們來取得People類別的建構器對象,有了這個建構器對象,我們便能夠建構出一個People對像出來。例如,我們可以在Student.java中加入以下程式碼:

public static void main(String[] args) {   
  Class<People> pClass = People.class;   
  try {   
    Constructor<People> constructor = pClass.getConstructor(String.class, int.class);     
    People people = constructor.newInstance("Bill", 18);                 
    people.speak();  
  } catch (Exception e) {  
  } 
}
登入後複製

在上面,我們呼叫getConstructor方法來取得一個People類別的建構器對象,由於我們想要取得的建構器的形參類型為String和int,所以我們傳入String.class和int.class。有了建構器對象,我們便可以呼叫newInstance方法來建立一個people對象。

注意,當透過反射取得到類別的Constructor、Method、Field物件後,在呼叫這些物件的方法之前,先將此物件的accessible 標誌設為true,以取消Java 語言存取檢查,可以提升反射速度。如以下程式碼所示:

Constructor<People> constructor = peopleClass.getConstructor(String.class, 
    int.class);
// 设置 constructor 的 Accessible属性为ture以取消Java的访问检查
constructor.setAccessible(true);
登入後複製

透過反射取得類別中宣告的方法

取得目前類別中宣告的方法(不包括從父類別繼承來的)

要取得目前類別中宣告的所有方法可以透過Class 中的getDeclaredMethods 函數,它會取得到目前類別中宣告的所有方法(包括private、public、static等各種方法),它會傳回一個Method物件數組,其中的每個Method物件即表示了一個類別中聲明的方法。想要取得指定的方法,可以呼叫getDeclaredMethod(String name, Class... parameterTypes)。如以下程式碼所示:

private static void showDeclaredMethods() {  
  Student student = new Student("Bill", 18);   
  //获取Student类声明的所有方法 
  Method[] methods = student.getClass().getDeclaredMethods();       
   try {      
      //获取learnMethod对象(封装了learn方法) 
      Method learnMethod = student.getClass().getDeclaredMethod("learn", 
          String.class);                
      //获取learn方法的参数列表并打印出来 
      Class<?>[] paramClasses = learnMethod.getParameterTypes() ;        
      for (Class<?> class : paramClasses) {      
        System.out.println("learn方法的参数: " + class.getName());    
      }                
      //判断learn方法是否为private 
      System.out.println(learnMethod.getName() + " is private " 
          + Modifier.isPrivate(learnMethod.getModifiers()));   
      //调用learn方法    
      learnMethod.invoke(student, "Java Reflection");  
    } catch (Exception e) {  
  }
}
登入後複製

取得目前類別和父類別中宣告的公有方法

要取得目前類別以及父類別中宣告的所有public 方法可以呼叫getMethods 函數,而要取得某個指定的public方法,可以呼叫getMethod方法。請看以下程式碼:

private static void showMethods() { 
  Student student = new Student("mr.simple");    
  // 获取所有public方法(包括Student本身的和从父类继承来的)  
  Method[] methods = student.getClass().getMethods();   
  try {    
    //注意,通过 getMethod只能获取public方法,若尝试获取private方法则会抛出异常 
    Method learnMethod = student.getClass().getMethod("learn", String.class);
  } catch (Exception e) {  
  }
}
登入後複製

透過反射取得類別中定義的屬性

取得屬性與取得方法是類似的,只不過把對getMethods() / getDeclaredMethods()方法的呼叫換成了對getFields() / getDeclaredFields()方法的呼叫。

取得目前類別中定義的屬性(不包括從父類別繼承來的屬性)

要取得目前類別中定義的所有屬性(包括private、public、static等各種屬性)可以呼叫Class物件的getDeclaredFields函數;要取得指定的屬性,可以呼叫getDeclaredField。如以下程式碼所示:

private static void showDeclaredFields() {   
  Student student = new Student("Bill", 18);    
  // 获取当前类中定义的所有属性  
  Field[] fields = student.getClass().getDeclaredFields();   
  try {    
    // 获取指定的属性 
    Field gradeField = student.getClass().getDeclaredField("grade"); 
    // 获取属性值 
    System.out.println("The grade is : " + gradeField.getInt(student));    
    // 设置属性值    
    gradeField.set(student, 10); 
   } catch (Exception e) { 
  } 
}
登入後複製

取得目前類別和父類別中定義的public屬性

要取得目前類別和父類別中定義的所有public 屬性可以呼叫Class物件的getFields 函數,而要取得某個指定的public屬性,可以呼叫getField方法,如以下程式碼所示:

private static void showFields() {  
  Student student = new Student("Bill", 18);            
  // 获取当前类和父类的所有public属性 
  Field[] publicFields = student.getClass().getFields();        
}
登入後複製

透過反射取得類別的父類別及類別所實作的介面

获取父类

调用Class对象的getSuperClass方法即可,如以下代码所示:

Student student = new Student("Bill", 18);
Class<?> superClass = student.getClass().getSuperclass();
登入後複製

获取所实现的接口

要知道一个类实现了哪些接口,只需调用Class对象的getInterfaces方法,如以下代码所示:

private static void showInterfaces() { 
  Student student = new Student("Bill", 19); 
  Class<?>[] interfaces = student.getClass().getInterfaces();
}
登入後複製

以上是怎麼理解java反射的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

創造未來:零基礎的 Java 編程 創造未來:零基礎的 Java 編程 Oct 13, 2024 pm 01:32 PM

Java是熱門程式語言,適合初學者和經驗豐富的開發者學習。本教學從基礎概念出發,逐步深入解說進階主題。安裝Java開發工具包後,可透過建立簡單的「Hello,World!」程式來實踐程式設計。理解程式碼後,使用命令提示字元編譯並執行程序,控制台上將輸出「Hello,World!」。學習Java開啟了程式設計之旅,隨著掌握程度加深,可創建更複雜的應用程式。

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

See all articles