4 回答
TA貢獻1789條經驗 獲得超8個贊
反射是一種語言在運行時檢查和動態調用類,方法,屬性等的能力。
例如,Java中的所有對象都有這個方法getClass(),即使您在編譯時不知道對象的類,也可以確定對象的類(例如,如果您將其聲明為Object) - 這可能看似微不足道,但這種反射是不可能的在動態較少的語言中C++。更高級的用法允許您列出和調用方法,構造函數等。
反射很重要,因為它允許您編寫程序,這些程序在編譯時不必“知道”所有內容,使它們更具動態性,因為它們可以在運行時綁定在一起。代碼可以針對已知接口編寫,但是可以使用配置文件中的反射來實例化要使用的實際類。
由于這個原因,許多現代框架廣泛使用反射。大多數其他現代語言也使用反射,并且在腳本語言(例如Python)中,它們甚至更緊密地集成,因為在這些語言的通用編程模型中感覺更自然。
TA貢獻1827條經驗 獲得超8個贊
我最喜歡使用的反射之一是下面的Java轉儲方法。它將任何對象作為參數,并使用Java反射API打印出每個字段名稱和值。
import java.lang.reflect.Array;import java.lang.reflect.Field;public static String dump(Object o, int callCount) {
callCount++;
StringBuffer tabs = new StringBuffer();
for (int k = 0; k < callCount; k++) {
tabs.append("\t");
}
StringBuffer buffer = new StringBuffer();
Class oClass = o.getClass();
if (oClass.isArray()) {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("[");
for (int i = 0; i < Array.getLength(o); i++) {
if (i < 0)
buffer.append(",");
Object value = Array.get(o, i);
if (value.getClass().isPrimitive() ||
value.getClass() == java.lang.Long.class ||
value.getClass() == java.lang.String.class ||
value.getClass() == java.lang.Integer.class ||
value.getClass() == java.lang.Boolean.class
) {
buffer.append(value);
} else {
buffer.append(dump(value, callCount));
}
}
buffer.append(tabs.toString());
buffer.append("]\n");
} else {
buffer.append("\n");
buffer.append(tabs.toString());
buffer.append("{\n");
while (oClass != null) {
Field[] fields = oClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
buffer.append(tabs.toString());
fields[i].setAccessible(true);
buffer.append(fields[i].getName());
buffer.append("=");
try {
Object value = fields[i].get(o);
if (value != null) {
if (value.getClass().isPrimitive() ||
value.getClass() == java.lang.Long.class ||
value.getClass() == java.lang.String.class ||
value.getClass() == java.lang.Integer.class ||
value.getClass() == java.lang.Boolean.class
) {
buffer.append(value);
} else {
buffer.append(dump(value, callCount));
}
}
} catch (IllegalAccessException e) {
buffer.append(e.getMessage());
}
buffer.append("\n");
}
oClass = oClass.getSuperclass();
}
buffer.append(tabs.toString());
buffer.append("}\n");
}
return buffer.toString();}TA貢獻1872條經驗 獲得超4個贊
反思的用途
反射通常由程序使用,這些程序需要能夠檢查或修改在Java虛擬機中運行的應用程序的運行時行為。這是一個相對高級的功能,只有那些掌握了語言基礎知識的開發人員才能使用??紤]到這一點,反射是一種強大的技術,可以使應用程序執行本來不可能的操作。
可擴展性功能
應用程序可以通過使用完全限定名稱創建可擴展性對象的實例來使用外部的用戶定義類。類瀏覽器和可視開發環境類瀏覽器需要能夠枚舉類的成員。可視化開發環境可以從利用反射中可用的類型信息中受益,以幫助開發人員編寫正確的代碼。調試器和測試工具調試器需要能夠檢查類中的私有成員。測試工具可以利用反射系統地調用類上定義的可發現的set API,以確保測試套件中的高級代碼覆蓋率。
反思的缺點
反思是強大的,但不應隨意使用。如果可以在不使用反射的情況下執行操作,則優選避免使用它。通過反射訪問代碼時,應牢記以下問題。
績效開銷
由于反射涉及動態解析的類型,因此無法執行某些Java虛擬機優化。因此,反射操作的性能低于非反射操作,并且應避免在性能敏感應用程序中頻繁調用的代碼段中。
安全限制
Reflection需要運行時權限,在安全管理器下運行時可能不存在。對于必須在受限安全上下文中運行的代碼,例如在Applet中,這是一個重要的考慮因素。
內部接觸
由于反射允許代碼執行在非反射代碼中非法的操作,例如訪問私有字段和方法,因此使用反射會導致意外的副作用,這可能導致代碼功能失常并可能破壞可移植性。反射代碼打破了抽象,因此可能會通過升級平臺來改變行為。
添加回答
舉報
