Java反射

一、Java反射

1.1 Java反射的定義

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
JAVA反射(放射)機制:“程序運行時,允許改變程序結構或變量類型,這種語言稱爲動態語言”。從這個觀點看,Perl,Python,Ruby是動態語言,C++,Java,C#不是動態語言。但是JAVA有着一個非常突出的動態相關機制:Reflection,用在Java身上指的是我們可以於運行時加載、探知、使用編譯期間完全未知的classes。換句話說,Java程序可以加載一個運行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其對象實體、或對其fields設值、或喚起其methods。

1.2 反射機制的作用:

  1. 反編譯:*.class–>*.java
  2. 通過反射機制訪問java對象的屬性,方法,構造方法等;

1.3 反射相關類

java.lang.Class;                
java.lang.reflect.Constructor; 
java.lang.reflect.Field;        
java.lang.reflect.Method;
java.lang.reflect.Modifier;

二、具體功能實現

2.1 反射機制獲取類有三種方法,我們來獲取Employee類型

//第一種方式:注意此處的Employee必須是全路徑名(包名+文件名)
Classc1 = Class.forName("Employee");
//第二種方式:
//java中每個類型都有class屬性.
Classc2 = Employee.class;
//第三種方式:
//java語言中任何一個java對象都有getClass 方法
Employeee = new Employee();
Classc3 = e.getClass(); //c3是運行時類 (e的運行時類是Employee)

2.2 創建對象:獲取類以後我們來創建它的對象,利用newInstance

Class c =Class.forName("Employee"); 
//創建此Class 對象所表示的類的一個新實例
Objecto = c.newInstance(); //調用了Employee的無參數構造方法.

2.3 獲取屬性:分爲所有的屬性和指定的屬性:

a,先獲取所有的屬性的寫法:

//獲取整個類
Class c = Class.forName("java.lang.Integer");
//獲取所有的屬性
Field[] fs = c.getDeclaredFields();
//定義可變長的字符串,用來存儲屬性
StringBuffer sb = new StringBuffer();
//通過追加的方法,將每個屬性拼接到此字符串中
//最外邊的public(訪問修飾符)定義
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");
//裏邊的每一個屬性
for(Field field:fs){
    sb.append("\t");//製表符           
    sb.append(Modifier.toString(field.getModifiers())+" ");//獲得屬性的修飾符,例如public,static等等
    sb.append(field.getType().getSimpleName() + " ");//屬性的類型的名字
    sb.append(field.getName()+";\n");//屬性的名字+回車
}
sb.append("}");
System.out.println(sb);

b,獲取特定的屬性,對比着傳統的方法來學習:

public static void main(String[] args) throws Exception {
    //以前的方式:  
    /* 
    User u = new User(); 
    u.age = 12; //set 
    System.out.println(u.age); //get 
    */

    //獲取類  
    Class c = Class.forName("User");
    //獲取id屬性  
    Field idF = c.getDeclaredField("id");
    //實例化這個類賦給o  
    Object o = c.newInstance();
    //打破封裝(JVM運行時不檢查屬性修飾符)  
    idF.setAccessible(true); //使用反射機制可以打破封裝性,導致了java對象的屬性不安全。  
    //給o對象的id屬性賦值"110"  
    idF.set(o, "110"); //set  
    //get  
    System.out.println(idF.get(o));
}

2.4 獲取方法,和構造方法,不再詳細描述,只來看一下關鍵字:

方法關鍵字 含義
getDeclaredMethods() 獲取所有的方法
getReturnType() 獲得方法的返回類型
getParameterTypes() 獲得方法的形式參數類型
getDeclaredMethod("方法名",參數類型.class,……) 獲得特定的方法
構造方法關鍵字 含義
getDeclaredConstructors() 獲取所有的構造方法
getDeclaredConstructor(參數類型.class,……) 獲取特定的構造方法
父類和父接口 含義
getSuperclass() 獲取某類的父類
getInterfaces() 獲取某類實現的接口

補充:在獲得類的方法、屬性、構造函數時,會有getXXXgetDeclaredXXX兩種對應的方法。之間的區別在於前者返回的是訪問權限爲public的方法和屬性,包括父類中的;但後者返回的是所有訪問權限的方法和屬性,不包括父類的。

三、Java反射總結

3.1 Java反射的一般用法(步驟)

使用java的反射機制,一般需要遵循三步:

  1. 獲得你想操作類的Class對象
  2. 通過第一步獲得的Class對象去取得操作類的方法或是屬性名
  3. 操作第二步取得的方法或是屬性

實例:

/**
 * Java 反射練習。
 */
public class ReflectionTest {
    public static void main(String[] args) throws Exception {
        DisPlay disPlay = new DisPlay();
        // 獲得Class
        Class<?> clazz = disPlay.getClass();
        // 通過Class獲得DisPlay類的show方法
        Method method = clazz.getMethod("show", String.class);
        // 調用show方法
        method.invoke(disPlay, "Hello");
    }
}

class DisPlay {
    public void show(String name) {
        System.out.println("Hello :" + name);
    }
}

3.2 Java反射分析

3.2.1 反射的用途 (Uses of Reflection)

反射被廣泛地用於那些需要在運行時檢測或修改程序行爲的程序中。這是一個相對高級的特性,只有那些語言基礎非常紮實的開發者才應該使用它。如果能把這句警示時刻放在心裏,那麼反射機制就會成爲一項強大的技術,可以讓應用程序做一些幾乎不可能做到的事情。(Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible.)

3.2.2 反射的缺點 (Drawbacks of Reflection)

儘管反射非常強大,但也不能濫用。如果一個功能可以不用反射完成,那麼最好就不用。在我們使用反射技術時,下面幾條內容應該牢記於心:(Reflection is powerful, but should not be used indiscriminately. If it is possible to perform an operation without using reflection, then it is preferable to avoid using it. The following concerns should be kept in mind when accessing code via reflection.)

性能第一 Performance Overhead Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications.
反射包括了一些動態類型,所以JVM無法對這些代碼進行優化。因此,反射操作的效率要比那些非反射操作低得多。我們應該避免在經常被 執行的代碼或對性能要求很高的程序中使用反射。

安全限制 Security Restrictions Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet. 使用反射技術要求程序必須在一個沒有安全限制的環境中運行。如果一個程序必須在有安全限制的環境中運行,如Applet,那麼這就是個問題了

內部暴露 Exposure of Internals Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform. 由於反射允許代碼執行一些在正常情況下不被允許的操作(比如訪問私有的屬性和方法),所以使用反射可能會導致意料之外的副作用--代碼有功能上的錯誤,降低可移植性。反射代碼破壞了抽象性,因此當平臺發生改變的時候,代碼的行爲就有可能也隨着變化。

參考JAVA中的反射機制JAVA反射機制-百度百科Java 反射機制淺析Java反射機制的缺點

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章