簡介
在new對象時,jvm在磁盤中找到類的"**.class"文件,由jvm將"**.class"加載到內存,爲該對象分配空間,並生成一個相應的類型類(class)對象,jvm自動完成類的實例化,這是類加載的正向流程。反射則是在運行時動態地手動獲取類中所有的屬性、方法,此時類屬性和方法在手動加載時均被加載爲對象,通過這些對象去訪問實際的屬性/方法。
public class Apple {
private int price;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public static void main(String[] args) throws Exception{
//正常的調用--------------
Apple apple = new Apple();
apple.setPrice(5);
System.out.println("Apple Price:" + apple.getPrice());
//使用反射調用------------------
Class clz = Class.forName("com.chenshuyi.api.Apple");// 獲得class對象,一個類只產生一個class對象
Method setPriceMethod = clz.getMethod("setPrice", int.class);// 獲得類中方法的對象
Constructor appleConstructor = clz.getConstructor();//調用構造函數的對象
Object appleObj = appleConstructor.newInstance();//使用構造函數的對象進行實例化
setPriceMethod.invoke(appleObj, 14);//使用函數對象通過invoke方法調用對應的函數
Method getPriceMethod = clz.getMethod("getPrice");
System.out.println("Apple Price:" + getPriceMethod.invoke(appleObj));
}
}
反射API用來生成JVM中的類、接口或則對象的信息。
- Class類:反射的核心類,可以獲取類的屬性,方法等信息。
- Field類:Java.lang.reflec包中的類,表示類的成員變量,可以用來獲取和設置類之中的屬性值。
- Method類: Java.lang.reflec包中的類,表示類的方法,它可以用來獲取類中的方法信息或者執行方法。
- Constructor類: Java.lang.reflec包中的類,表示類的構造方法。
2. 反射的用途
2.1 運行時配置文件
由於在運行時,動態加載class對象,動態獲取對象屬性和方法,因此可以將屬性和方法配置在文件中,可在程序運行時對class文件和屬性、函數即改即生效。
2.2 越過泛型檢查
泛型用在編譯期,編譯過後泛型擦除(消失掉)。所以是可以通過反射越過泛型檢查的,因此使用反射可以在List<String>中添加int數據。
總結
反射被廣泛地用於那些需要在運行時檢測或修改程序行爲的程序中。這是一個相對高級的特性,只有那些語言基礎非常紮實的開發者才應該使用它。如果能把這句警示時刻放在心裏,那麼反射機制就會成爲一項強大的技術,可以讓應用程序做一些幾乎不可能做到的事情。
儘管反射非常強大,但也不能濫用。如果一個功能可以不用反射完成,那麼最好就不用。
在我們使用反射技術時,下面幾條內容應該牢記於心:
- 反射包括了一些動態類型,所以 JVM 無法對這些代碼進行優化。因此,反射操作的效
率要比那些非反射操作低得多。我們應該避免在經常被 執行的代碼或對性能要求很高的程
序中使用反射。 - 使用反射技術要求程序必須在一個沒有安全限制的環境中運行。如果一個程序必須在有
安全限制的環境中運行,如 Applet,那麼這就是個問題了。 - 由於反射允許代碼執行一些在正常情況下不被允許的操作(比如訪問私有的屬性和方
法),所以使用反射可能會導致意料之外的副作用--代碼有功能上的錯誤,降低可移植性。
反射代碼破壞了抽象性,因此當平臺發生改變的時候,代碼的行爲就有可能也隨着變化。