框架是個好東西,可早晚有一天會過時,這世界上就沒有亙古不變的東西,來學下Java基礎吧
反射機制
Java語言的反射機制是指:在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法,對於任意一個對象,都能夠調用他的任意一個屬性和方法,這種動態獲取的信息以及動態調用對象的方法的功能成爲反射機制
如何獲取這些信息呢?依賴於Class對象,Class對象將一個類的方法,變量等信息告訴運行的程序
獲取Class對象的兩種方法:
已知類名爲TargetObject
- Class alunbarClass = TargetObject.class;
- Class alunbarClass1 = Class.forName("cn.luckycurve.TargetObject");
反射使用實例
供調用的TargetObject類
public class TargetObject {
private String value;
public TargetObject() {
value = "LuckyCurve";
}
public void publicMethod(String name) {
System.out.println("I love " + name);
}
private void privateMethod(String name) {
System.out.println("I hate " + name);
}
}
調用Target的Main類
public class Main {
// 操作Traget類
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
Class<?> targetClass = Class.forName("cn.luckycurve.demo9.TargetObject");
// 從Java 9 開始不推薦使用以下寫法
// TargetObject o = (TargetObject) targetClass.newInstance();
// 推薦寫法爲
TargetObject target = (TargetObject) targetClass.getDeclaredConstructor().newInstance();
// 獲取類中的所有方法
Method[] methods = targetClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println("method name :" + method.getName());
}
// 獲取指定方法並調用,要指定方法名和參數信息
Method publicMethod = targetClass.getDeclaredMethod("publicMethod", String.class);
// 由於是非靜態方法,要指定調用方法的對象
publicMethod.invoke(target, "Java");
// 直接獲取和修改private類型的字段
Field value = targetClass.getDeclaredField("value");
// 因爲value是private的,取消安全檢查,不然會拋出異常
value.setAccessible(true);
String string = (String) value.get(target);
System.out.println("修改前 value:" + string);
value.set(target,"LuckyCurve2");
String string2 = (String) value.get(target);
System.out.println("修改後 value:" + string2);
// 調用私有方法
Method privateMethod = targetClass.getDeclaredMethod("privateMethod", String.class);
// 取消安全檢查
privateMethod.setAccessible(true);
privateMethod.invoke(target,"lazy");
}
}
<<<method name :publicMethod
<<<method name :privateMethod
<<<I love Java
<<<修改前 value:LuckyCurve
<<<修改後 value:LuckyCurve2
<<<I hate lazy
總結:
1.調用非靜態方法,要將對象傳進invoke方法中
2.所有聲明爲private的字段和方法,在使用前都要調用feild.setAccessible(true)或者method.setAccessible(true)來解除安全檢查
靜態編譯和動態編譯
- 靜態編譯:在編譯時確定類型,綁定對象
- 動態編譯:在運行時確定類型,綁定對象
C++裏面有詳細的描述(C++的語言顆粒度細,程序很容易涉及到底層)
反射的優缺點
- 優點:動態編譯,增加了靈活性
- 缺點:運行效率低,需要JVM進行一系列解釋操作。安全問題,反射甚至可以操作私有字段和方法(也是優點,增加了靈活性 )
反射的應用場景
反射是框架的靈魂
雖然開發的時候很難用到反射機制,但也不能說明反射機制沒有什麼用,動態代理的設計模式,模塊化的開發,還有我們日常使用的Spring / Hibernate等框架,都大量用到了反射機制
- JDBC連接數據庫時候使用了Class.forName
- Spring框架的IOC以及AOP
- …