您好,登錄后才能下訂單哦!
本篇內容介紹了“使用Java反射的步驟是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
1、概念
反射,指在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法,對任意一個對象,都能調用它的任意一個方法。這種動態獲取信息,以及動態調用對象方法的功能,叫做java語言的反射機制。反射很強大,有優點也有缺點。
優點:靈活性高。因為反射屬于動態編譯,即只有到運行時才動態創建 &獲取對象實例。
缺點:執行效率低。
2.1 元數據的概念
元數據(metadata):元數據是指用來描述類的數據,就是class的代碼數據。所有的class文件加載到虛擬機之后都會被構建成class對象,class對象描述了一個類都有哪些東西,大家都知道的實現的接口,繼承的抽象類,成員變量,類變量,成員方法,類方法,靜態方法等,這個class對象就是元數據。
Class類:代表一個類。
Field類:代表類的成員變量(成員變量也稱為類的屬性)。
Method類:代表類的方法。
Constructor類:代表類的構造方法。
編輯 搜圖
2.2 獲取class對象的方式
2.2.1 通過對象獲得,因為任何對象都必須和class對象關聯
2.2.2 通過類對象直接獲得
2.2.3 通過類加載器獲得,因為類加載器讀取class文件會返回class對象
即將用來反射的對象(隨便定義的一個對象,只是為了演示)
package org.pdool.reflect;
/**
* @author 香菜
*/
public class Npc {
// 靜態field
public static int NPC_TYPE_1 = 1;
// 私有成員變量
private int npcType;
// 共有成員變量
public String name;
// 無參構造函數
public Npc() {
}
// 有參構造函數
public Npc(int npcType, String name) {
this.npcType = npcType;
this.name = name;
}
public int getNpcType() {
return npcType;
}
public void setNpcType(int npcType) {
this.npcType = npcType;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 靜態方法
public static void sayHello(String word){
System.out.println("hello " + word);
}
}
獲取反射class的三種方式
package org.pdool.reflect;
/**
* @author 香菜
*/
public class ClazzTest {
public static void main(String[] args) {
//第一種方式獲取Class對象
Npc npc1 = new Npc();//這一new 產生一個Npc對象,一個Class對象。
Class npcClazz1 = npc1.getClass();//獲取Class對象
System.out.println(npcClazz1.getName());
//第二種方式獲取Class對象
Class npcClazz2 = Npc.class;
System.out.println(npcClazz1 == npcClazz2);//判斷第一種方式獲取的Class對象和第二種方式獲取的是否是同一個
//第三種方式獲取Class對象
try {
Class npcClazz3 = Class.forName("org.pdool.reflect.Npc");//注意此字符串必須是真實路徑,就是帶包名的類路徑,包名.類名
System.out.println(npcClazz3 == npcClazz2);//判斷三種方式是否獲取的是同一個Class對象
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
1、訪問權限
反射機制的默認行為受限于
Java的訪問控制,可通過 setAccessible 繞過控制。
// 設置對象數組可訪問標志
static void setAccessible(AccessibleObject[] array, boolean flag)
2、獲取方法
編輯 搜圖
2.1 訪問靜態方法
public static void main(String[] args) throws NoSuchMethodException,InvocationTargetException, IllegalAccessException {
Npc npc = new Npc(1, "妖神·凰女");
Class npcClazz = Npc.class;
// 第一個參數是方法名,第二個參數是函數的參數class對象,因為存在重載的可能性,用參數類型區分
Method sayHello = npcClazz.getMethod("sayHello", String.class);
sayHello.invoke(npc, "world");
}
2.2 訪問類方法
Npc npc = new Npc(1, "妖神·凰女");
System.out.println(npc.getName());
Class npcClazz = Npc.class;
// 第一個參數是方法名,第二個參數是函數的參數class對象,因為存在重載的可能性,用參數類型區分
Method sayHello = npcClazz.getMethod("setName", String.class);
sayHello.invoke(npc, "world");
System.out.println(npc.getName());
3、獲取字段,讀取字段的值
編輯 搜圖
Npc npc = new Npc(1, "妖神·凰女");
Class npcClazz = Npc.class;
// 獲取字段,并設置可訪問
Field field = npcClazz.getField("name");
field.setAccessible(true);
System.out.println( field.get(npc));
4、獲取實現的接口
編輯 搜圖
5、獲取構造函數,創建實例
編輯 搜圖
Class npcClazz = Npc.class;
Constructor declaredConstructor = npcClazz.getDeclaredConstructor(int.class,String.class);
Npc npc = (Npc) declaredConstructor.newInstance(1, "妖神");
System.out.println(npc.getName());
6、獲取繼承的父類
Class npcClazz = Npc.class;
Class superclass = npcClazz.getSuperclass();
System.out.println(superclass.getName());
7、獲取注解
Class npcClazz = Npc.class;
Annotation[] annotations = npcClazz.getAnnotations();
// 運行時注解
for (Annotation annotation : annotations) {
System.out.println(annotation.getClass().getName());
}
獲取到元數據不是最終的目的,我們最終的目的是想在運行時去調用,訪問類。說了太多,還是舉個例子,大家都知道Spring的IOC,怎么實現的吶?
過程:
1、Spring 在項目啟動的時間通過讀取xml中配置的bean的路徑,
2、然后通過Class.forName 讀取class 到類加載器,
3、然后通過反射創建所有的bean實例并保存到容器中,啟動容器之后,
4、在項目中可以直接獲取bean對象。
我們來大概實現這一過程,因為xml的讀取比較麻煩,直接用property來代替了。大家體會一下思想就可以了。
package org.pdool.reflect;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
/**
* @author 香菜
*/
public class ClazzTest {
public static void main(String[] args){
try {
Map<String,Object> container = new HashMap<>();
//1.讀取配置
InputStream in = ClazzTest.class.getResourceAsStream("/beans.properties");
Properties property = new Properties();
property.load(in);
//2.反射創建對象
Set<Object> keySet = property.keySet();
for (Object key : keySet) {
// 2.1 獲取類的全路徑
String classStr = (String) property.get(key);
// 2.2 加載class 到虛擬機
Class<?> beanClazz = Class.forName(classStr);
// 2.3 獲取缺省的構造函數
Constructor<?> declaredConstructor = beanClazz.getDeclaredConstructor();
// 2.4 創建實例
Object o = declaredConstructor.newInstance();
container.put((String) key,o);
}
// 3.獲取實例
Npc npc = (Npc) container.get("npc");
System.out.println(npc == null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
在使用Java反射機制時,主要步驟包括:
1.獲取 目標類型的Class對象
2.通過 Class 對象分別獲取Constructor類對象、Method類對象 或者 Field 類對象
3.通過 Constructor類對象、Method類對象 & Field類對象分別獲取類的構造函數、方法&屬性的具體信息,并進行后續操作。
“使用Java反射的步驟是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。