
1. 反射的概念
反射 機制指的是,程式在運行時能夠獲取自身的資訊,在 java 中只要給定類的名字,就能夠獲取類的所有屬性和方法,
反射是 Java 中很多高級特性的基礎,比如 注解、動態代理 以及 Spring Ioc、AOP 等技術都需要借助反射來實作,
2. Class 物件的創建
java 中 java.lang.Class 是反射機制的基礎,當我們想要在運行期獲取一個類中的相關資訊的時候,必須先獲取其 Class 類,Jvm 會自動將已加載類的 Class 對像載入,
獲取 Class 物件的三種方式:
-
物件實體.getClass()
MyObject obj = new MyObject();Class clazz = obj.getClass();
-
類名.Class
Class clazz = MyObject.Class; -
Class.forName()
Class clazz = Class.forName("MyObject");
3. 通過反射創建實體
java 中,最常使用的創建實體方法是通過 new 關鍵字來實作的,使用反射,也有兩種可以 創建實體 的方式,
使用 Class 物件的 newInstance() 方法
Class clazz = MyObject.class;
MyObject myObject = clazz.newInstance();
使用 java.lang.reflet.Constructor 中的 newInstance() 方法
Constructor<MyObject> constructor = MyObject.class.getConstructor();
MyObject myObject = constructor.newInstance();
說明:其實 clazz.newInstance() 創建實體的內部也是通過 Constructor 創建實體的方式來實作的
4. 通過反射獲取類的屬性、方法、注解、構造器
Class 類中有獲取類的所有 屬性、方法、注解、構造器的相關方法,如下:
獲取 非私有的 屬性、方法、注解、構造器
Field[] getFields(); // 獲取屬性
Method[] getMethods(); // 獲取方法
Annotation[] getAnnotations(); // 獲取注解
Constructor<?>[] getConstructors(); // 獲取構造器
獲取** 私有的** 屬性、方法、注解、構造器
Field[] getDeclaredFields(); // 獲取私有屬性
Method[] getDeclaredMethods(); // 獲取私有方法
Annotation[] getDeclaredAnnotations(); // 獲取私有注解
Constructor<?>[] getDeclaredConstructors(); // 獲取私有構造器
使用示例:
Class clazz = MyObject.class;
Methods[] methodList = clazz.getFields();
5. 反射機制的一些缺點
-
反射會破壞封裝性:由于反射允許代碼執行一些在正常情況下不被允許的操作(比如訪問私有的屬性和方法),所以使用反射可能會導致意料之外的副作用--代碼有功能上的錯誤,降低可移植性,反射代碼破壞了抽象性,因此當平臺發生改變的時候,代碼的行為就有可能也隨著變化,
-
反射的性能問題:反射包括了一些動態型別,所以 JVM 無法對這些代碼進行優化,因此,反射操作的效率要比那些非反射操作低得多,我們應該避免在經常被 執行的代碼或對性能要求很高的程式中使用反射,
-
安全性問題:使用反射技術要求程式必須在一個沒有安全限制的環境中運行,如果一個程式必須在有安全限制的環境中運行,如 Applet,那么這就是個問題了,
6. 反射對單例的破壞
單例是為了控制 類示例 在記憶體中只存在一個的機制,他本身的構造方法是 private 的,對外提供 getSingleton() 方法,統一管理實體的獲取,
而反射可以通過獲取到類中的私有構造方法, 并將其變為可用,通過構造方法生成新的實體,這樣就造成了單例的破壞,
雙重校驗鎖的單例模式:
public class Singleton {
private static volatile Singleton singleton();
private Singleton() {
}
public static Singleton getSingleton() {
if(singleton == null) {
synchronized (Singleton.class) {
if(singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
通過反射破壞單例:
Singleton singleton1 = Singleton.getSingleton();
// 通過反射獲取建構式
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
// 將構造方法設定為可訪問
constructor.setAccessible(true);
// 通過構造方法創建一個新的實體
Singleton singleton2 = constructor.newInstance();
System.out.print(singleton1 == singleton2); // false
解決方案:在單例類的構造方法中加判斷,當實體已存在的時候,不再創建新的實體
private Singleton() {
if(singleton != null) {
throw new RuntimeException("單例物件只能創建一次...");
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/539318.html
標籤:其他
下一篇:JAVA里Map的一些常用方法
