java之反射,java反射

來源:互聯網
上載者:User

java之反射,java反射

java之反射
一、Java Reflection
     Reflection(反射)是被視為動態語言的關鍵,反射機制允許程式在執行期藉助於Reflection API取得任何類的內部資訊,
     並能直接操作任意對象的內部屬性及方法
①Java反射機制提供的功能
    在運行時判斷任意一個對象所屬的類
    在運行時構造任意一個類的對象
    在運行時判斷任意一個類所具有的成員變數和方法
    在運行時調用任意一個對象的成員變數和方法
    產生動態代理
②反射相關的主要API:
    java.lang.Class:代表一個類
    java.lang.reflect.Method:代表類的方法
    java.lang.reflect.Field:代表類的成員變數
    java.lang.reflect.Constructor:代表類的構造方法
二、Class 類
①Class本身也是一個類
    java.lang.Class:是反射的源頭。
    我們建立了一個類,通過編譯(javac.exe),產生對應的.class檔案。之後我們使用java.exe載入(JVM的類載入器完成的)
    此.class檔案,此.class檔案載入到記憶體以後,就是一個運行時類,存在在緩衝區。那麼這個運行時類本身就是一個Class的執行個體!
    1.每一個運行時類只載入一次!
    2.有了Class的執行個體以後,我們才可以進行如下的操作:
        1)*建立對應的運行時類的對象
        2)擷取對應的運行時類的完整結構(屬性、方法、構造器、內部類、父類、所在的包、異常、註解、...)
        3)*調用對應的運行時類的指定的結構(屬性、方法、構造器)
        4)反射的應用:動態代理
②Class類的常用方法
    static Class  forName(String name) :載入並返回指定類名 name 的 Class 對象
    Object newInstance() :調用預設建構函式,返回該Class對象的一個執行個體
    String getName() :返回此Class對象所表示的實體(類、介面、數組類、基本類型或void)名稱
    Class getSuperClass():返回當前Class對象的父類的Class對象
    Class [] getInterfaces() :擷取當前Class對象的介面
    ClassLoader getClassLoader() :返回該類的類載入器
    Constructor[] getConstructors():返回一個包含某些Constructor對象的數組
    Field[] getFields():返回Field對象的一個數組
    Method getMethod(String name,Class  …  paramTypes):返回一個Method對象,此對象的形參類型為paramType
③執行個體化Class類對象(四種方法)
1)前提:若已知具體的類,通過類的class屬性擷取,該方法 最為安全可靠,程式效能最高
       執行個體:Class clazz = String.class;
2)前提:已知某個類的執行個體,調用該執行個體的getClass()方法擷取Class對象
       執行個體:Class clazz = new String().getClass();
3)前提:已知一個類的全類名,且該類在類路徑下,可通過Class類的靜態方法forName(類的全類名)擷取,可能拋出ClassNotFoundException
       執行個體:Class clazz = Class.forName(“java.lang.String”);
4)其他:通過類載入器去載入
       ClassLoader loader = this.getClass().getClassLoader();
       Class clazz4 = loader.loadClass(“java.lang.String”);
④瞭解:類的載入過程
當程式主動使用某個類時,如果該類還未被載入到記憶體中,則系統會通過如下三個步驟來對該類進行初始化
  1)將類的class檔案讀入記憶體,並為之建立一個java.lang.Class對象。此過程由類載入器完成
  2)將類的位元據合并到JRE中
  3)JVM負責對類進行初始化
⑤瞭解:ClassLoader類載入器
類載入器是用來把類(class)裝載進記憶體的。JVM 規範定義了兩種類型的類載入器:
啟動類載入器(bootstrap)和使用者自訂載入器(user-defined class loader)。
JVM在運行時會產生3個類載入器組成的初始化載入器階層
  1)引導類載入器:用C++編寫的,是JVM內建的類載入器,負責Java平台核心庫,用來載入核心類庫。該載入器無法直接擷取
  2)擴充類載入器:負責jre/lib/ext目錄下的jar包或 –D java.ext.dirs 指定目錄下的jar封裝入工作庫
  3)系統類別載入器:負責java –classpath 或 –D java.class.path所指的目錄下的類與jar封裝入工作 ,是最常用的載入器
    //1.擷取一個系統類別載入器
    ClassLoader classloader = ClassLoader.getSystemClassLoader();
    System.out.println(classloader);
    //2.擷取系統類別載入器的父類載入器,即擴充類載入器
    classloader = classloader.getParent();
    //3.擷取擴充類載入器的父類載入器,即引導類載入器
    classloader = classloader.getParent();
    //4.測試當前類由哪個類載入器進行載入
    classloader = Class.forName("exer2.ClassloaderDemo").getClassLoader();
    //5.測試JDK提供的Object類由哪個類載入器載入
    classloader = Class.forName("java.lang.Object").getClassLoader();
    //*6.關於類載入器的一個主要方法:getResourceAsStream(String str):擷取類路徑下的指定檔案的輸入資料流
    InputStream in = this.getClass().getClassLoader().getResourceAsStream("exer2\\test.properties");
三、建立類對象並擷取類的完整結構
①建立類的對象:調用Class對象的newInstance()方法
要  求:1)類必須有一個無參數的構造器。
 2)類的構造器的存取權限需要足夠。
若沒有無參的構造器,只能在操作的時候明確的調用類中的構造方法,並將參數傳遞進去之後,才可以執行個體化操作。步驟如下:
        1)通過Class類的getDeclaredConstructor(Class … parameterTypes)取得本類的指定形參類型的構造器
        2)向構造器的形參中傳遞一個對象數組進去,裡麵包含了構造器中所需的各個參數。
        3)調用Constructor類的newInstance(object ... args)
②通過反射調用類的完整結構
②①擷取對應的運行時類的屬性 java.lang.reflect.Field
     1)Field[] getFields():只能擷取到運行時類中及其父類中聲明為public的屬性
     2)Field[] getDeclaredFields():擷取運行時類本身聲明的所有的屬性
     3)Field getField(String fieldName):擷取運行時類中聲明為public的指定屬性名稱為fieldName的屬性
     4)Field getDeclaredField(String fieldName):擷取運行時類中指定的名為fieldName的屬性,可以擷取所有的屬性,包括private屬性
     5)擷取屬性的各個部分的內容(許可權修飾符  變數類型 變數名)
          1.擷取每個屬性的許可權修飾符
       int i = feild.getModifiers();返回代表修飾符的一個整數
       String str1 = Modifier.toString(i);通過Modifier的toString()將數值轉化為字串
   2.擷取屬性的類型
       Class type = feild.getType();:返回屬性類型的Class對象
   3.擷取屬性名稱
       String str = feild.getName();返回屬性的名稱
     6)修改屬性值方法一 (public String name;)
                Class clazz = Person.class;
         //1.擷取指定的屬性getField(String fieldName):擷取運行時類中聲明為public的指定屬性名稱為fieldName的屬性
  Field name = clazz.getField("name");
  //2.建立運行時類的對象
  Person p = (Person)clazz.newInstance();
  System.out.println(p);
  //3.將運行時類的指定的屬性賦值
  name.set(p,"Jerry");
     7)修改屬性值方法二 (private int age;)
          //getDeclaredField(String fieldName):擷取運行時類中指定的名為fieldName的屬性
  Field age = clazz.getDeclaredField("age");
   //由於屬性許可權修飾符的限制,為了保證可以給屬性賦值,需要在操作前使得此屬性可被操作。
  age.setAccessible(true);
  age.set(p,10);
②②擷取運行時類的方法 java.lang.reflect.Method
     1)Method[] getMethods():擷取運行時類及其父類中所有的聲明為public的方法
     2)Method[] getDeclaredMethods():擷取運行時類本身聲明的所有的方法
     3)Method getMethod(String methodName,Class ... params):擷取運行時類中聲明為public的指定的方法
     4)Method getDeclaredMethod(String methodName,Class ... params):擷取運行時類中聲明了的指定的方法
     5)擷取方法的各個部分的內容(註解 許可權修飾符 返回值類型 方法名 形參列表 異常)
         //1.註解
  Annotation[] ann = method.getAnnotations();
  //2.許可權修飾符
  String str = Modifier.toString(method.getModifiers());
  //3.返回值類型
  Class returnType = method.getReturnType();
  //4.方法名
  String str = method.getName();
  //5.形參列表
  Class[] params = method.getParameterTypes();
  //6.異常類型
  Class[] exps = method.getExceptionTypes();
     6)調用運行時類中指定的方法一 [public void show()]
                Class clazz = Person.class;
  //getMethod(String methodName,Class ... params):擷取運行時類中聲明為public的指定的方法
  Method method = clazz.getMethod("show");
  Person p = (Person)clazz.newInstance();
  //調用指定的方法:Object invoke(Object obj,Object ... obj)
  Object returnVal = m1.invoke(p);  :返回調用方法的返回值
  System.out.println(returnVal);

  //對於運行時類中靜態方法的調用[public static void info()]
  Method method = clazz.getMethod("info");
  method.invoke(Person.class);
     7)調用運行時類中指定的方法二 [private int show(String nation,int age)] 
         //getDeclaredMethod(String methodName,Class ... params):擷取運行時類中聲明了的指定的方法
  Method method = clazz.getDeclaredMethod("display",String.class,int.class);
  //由於屬性許可權修飾符的限制,為了保證可以給屬性賦值,需要在操作前使得此屬性可被操作。 
  method.setAccessible(true);
  Object value = method.invoke(p,"CHN",10);
  System.out.println(value);
②③擷取運行時類的構造器 java.lang.reflect.Constructor
      1)public Constructor<T>[] getConstructors()返回此 Class 對象所表示的類的所有public構造方法。
      2)public Constructor<T>[] getDeclaredConstructors()返回此 Class 對象表示的類聲明的所有構造方法
      3)public Constructor<T> getConstructor(Class<?>... parameterTypes) :返回指定的public的構造器
      4)public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回類中聲明了的指定的構造器,包括private構造器
      5)調用運行時類中指定的構造器一
                String className = "com.lang.String";
  Class clazz = Class.forName(className);
   //建立對應的運行時類的對象。使用newInstance(),實際上就是調用了運行時類的空參的構造器。
  //要想能夠建立成功:①要求對應的運行時類要有空參的構造器。②構造器的許可權修飾符的許可權要足夠。
  Object obj = clazz.newInstance();
  String p = (String)obj;
      6)調用運行時類中指定的構造器二
                String1 className = "com.lang.String1";
  Class clazz = Class.forName(className);

                Constructor cons = clazz.getConstructor(String.class,int.class);
                String1 p = (String1)cons.newInstance("小三",20);
  
  Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
  cons.setAccessible(true);
  String1 p = (String1)cons.newInstance("小三",20);
②④擷取運行時類的註解
  Class clazz = String.class;
  Annotation[] anns = clazz.getAnnotations();
  for(Annotation a : anns){
   System.out.println(a);
  }
②⑤擷取運行時類所在的包
  Class clazz = String.class;
  Package pack = clazz.getPackage();
  System.out.println(pack);
 
②⑥擷取運行時類的實現的介面
  Class clazz = Person.class;
  Class[] interfaces = clazz.getInterfaces();
  for(Class i : interfaces){
   System.out.println(i);
  }
 
②⑦*.擷取運行時類的父類的泛型
  Class clazz = Person.class;
  Type type1 = clazz.getGenericSuperclass();
  
  ParameterizedType param = (ParameterizedType)type1;
  Type[] ars = param.getActualTypeArguments();
  
  System.out.println(((Class)ars[0]).getName());
②⑧擷取帶泛型的父類
  Class clazz = Person.class;
  Type type1 = clazz.getGenericSuperclass();
  System.out.println(type1);
 
②⑨擷取運行時類的父類
  Class clazz = Person.class;
  Class superClass = clazz.getSuperclass();
  System.out.println(superClass);


java中反射怎理解?

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法;這種動態擷取的資訊以及動態調用對象的方法的功能稱為java語言的反射機制。
Java反射機制主要提供了以下功能: 在運行時判斷任意一個對象所屬的類;在運行時構造任意一個類的對象;在運行時判斷任意一個類所具有的成員變數和方法;在運行時調用任意一個對象的方法;產生動態代理。
 
java中的反射機制是什?

JAVA反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法;這種動態擷取的以及動態調用對象的方法的功能稱為java語言的反射機制
 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.