【Java基礎】Java中的反射機制


一、反射的理解

(1)正射

在理解反射這個概念之前,我們先來理解Java中的“正射”。

我們在編寫代碼時,當需要使用到某一個類的時候,必定先會去了解這是一個什么類,是用來做什么的,有怎么樣的功能。

之后我們才對這個類進行實例化,之后再使用這個類的實例化對象進行操作。

Person person = new Person();
person.sleep("8:00");

(2)反射

上面的栗子介紹了什么是“正射”,以及“正射”的一般代碼實現;

而反射則是在代碼一開始編寫時不知道要初始化的類是什么。因此,自然也無法使用new關鍵字來創建對象了。

而當我們之后得到我們要初始化的類的名稱及路徑時,我們就可以使用JDK提供的反射API進行反射調用。

Class clazz = Class.forName("com.test.domain.Person");
Method method = clazz.getMethod("sleep", String.class);
Constructor constructor = clazz.getConstructor();
Object object = constructor.newInstance();
method.invoke(object, "8:00");

以上兩段代碼,其結果都是一樣的,但是其實現的過程卻有很大的差別:

  • 第一段代碼在未運行前就已經確定了要運行的類(Person);
  • 第二段代碼則是在整個程序運行時從某些地方(例:配置文件)獲取到相應的字符串值才能知道要運行的類("com.test.domain.Person")。

 

二、反射的應用

在我們日常的生產環境中,很少會直接使用到反射,但這並不代表反射在實際應用中很少。相反反射在Java中的框架使用得十分的多,反射是框架設計的靈魂:

①:spring、hibernate中會使用到反射機制,最常見的就是使用XML配置文件獲取對應的類,然后再加載;

②:真的好多啊。。。

三、反射的常用函數

(1)獲取反射中的class對象

在反射中,要獲取一個類或調用一個類的方法,首先必須要獲取到該類的對象,在Java API中,獲取Class類對象三種方法:

①:Class.forName("類的路徑名");

Class clazz = Class.forName("com.test.domain.Person");

②:利用已有類對象的getClass()方法;

Person person = new Person();
Class clazz = person.getClass();

③:對於在編譯前就已經知道的類,可以使用.class屬性;

Class clazz = Person.class;

(2)通過反射創建類對象

通過反射建立類的對象,Java API提供了兩種方式:

①:通過class對象的newInstance()方法;

Class clazz = Class.forName("com.test.domain.Person"); 
Person person
= (Person)clazz.newInstance();

②:通過Constructor對象的newInstance()方法;

Class clazz = Class.forName("com.test.domain.Person");
Constructor con = clazz.getConstructor();
Person person = (Person)con.newInstance();

(3)通過反射操作成員變量

①:獲取所有成員getFields()&getDeclaredFields();

使用getFields()方法可以獲取Class類的成員變量,但是無法獲取私有屬性。

Class clazz = Class.forName("com.test.domain.Person");
Field[] fields = clazz.getFields();
for (Field field : fields) {
  System.out.print(field.getName());
}

②:獲取單個成員getField()&getDeclared

③:修改成員變量的值set(Object obj, Object value)

Class clazz = Class.forName("com.test.domain.Person");
Person person = (Person)clazz.newInstance();
Field field = clazz.getField("name");
field.set(person, "張三");

當屬性為private時,這是我們無法直接使用set()方法修改它的值,此時應該使用setAccessible()方法取得訪問權限:

Class clazz = Class.forName("com.test.domain.Person");
Person person = (Person)clazz.newInstance();
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);
field.set(person, "張三");

(4)通過反射操作成員方法

①:獲取所有方法getMethods()&getDeclaredMethods()

②:獲取單個成員getMethod()&getDeclaredMethod()

操作方法與操作變量相差不大,在獲取到對應方法之后使用invoke()方法執行即可。同理,遇見私有方法時,也需要使用setAccessible(true)方法獲取訪問權限。

Class clazz = Class.forName("com.test.domain.Person");
Person person = (Person)clazz.newInstance();
Method method = clazz.getMethod("setName", String.class);
method.setAccessible(true);
method.invoke("李四");

通常情況下,即便得到的是當前類,private修飾的屬性或方法也是沒有權限訪問的,你需要設置訪問權限setAccessible(true)來取得訪問權限,但在實際上,這已經破壞了規則,所以應該盡量少地使用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM