摘要:通過反射獲取無參構造方法并使用得到無參構造方法獲取所有的修飾的構造方法。如果方法沒有返回值,返回的是反射獲取空參數成員方法并運行代碼演示反射獲取成員方法并運行獲取對象中的成員方法獲取的是文件中的所有公共成員方法包括繼承的類是描述
01類加載器
* A.類的加載 當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,連接,初始化三步來實現對這個類進行初始化。 ? * a 加載 * 就是指將class文件讀入內存,并為之創建一個Class對象。 * 任何類被使用時系統都會建立一個Class對象 ? * b 連接 * 驗證 是否有正確的內部結構,并和其他類協調一致 * 準備 負責為類的靜態成員分配內存,并設置默認初始化值 * 解析 將類的二進制數據中的符號引用替換為直接引用 ? * c 初始化 * 就是我們以前講過的初始化步驟(new 對象) * 注:簡單的說就是:把.class文件加載到內存里,并把這個.class文件封裝成一個Class類型的對象。 * B.類的加載時機 以下的情況,會加載這個類。 * a. 創建類的實例 * b. 類的靜態變量,或者為靜態變量賦值 * c. 類的靜態方法 * d. 使用反射方式來強制創建某個類或接口對應的java.lang.Class對象 * e. 初始化某個類的子類 * f. 直接使用java.exe命令來運行某個主類 * C: 類加載器(了解) 負責將.class文件加載到內在中,并為之生成對應的Class對象。 * a. Bootstrap ClassLoader 根類加載器 * 也被稱為引導類加載器,負責Java核心類的加載 * 比如System,String等。在JDK中JRE的lib目錄下rt.jar文件中
? * b. Extension ClassLoader 擴展類加載器
* 負責JRE的擴展目錄中jar包的加載。 * 在JDK中JRE的lib目錄下ext目錄
? * c. System ClassLoader 系統類加載器
* 負責在JVM啟動時加載來自java命令的class文件,以及classpath環境變量所指定的jar包和類路徑。 * 我們用的是System ClassLoader 系統類加載器02反射
* A. 反射定義 * a. JAVA反射機制是在運行狀態中, 對于任意一個類,都能夠知道這個類的所有屬性和方法; 對于任意一個對象,都能夠調用它的任意一個方法和屬性; 這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。 * b.反射技術 條件:運行狀態 已知:一個類或一個對象(根本是已知.class文件) 結果:得到這個類或對象的所有方法和屬性 * 注: 要想解剖一個類,必須先要獲取到該類的字節碼文件對象。而解剖使用的就是Class類中的方法.所以先要獲取到每一個字節碼文件對應的Class類型的對象。 * B. Class類 * a. Class類及Class對象的了解 要想解剖一個類,必須先了解Class對象。 閱讀API的Class類得知,Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的 defineClass 方法自動構造的。 * b. 得到Class對象 * 1. 有三個方法 方式一: 通過Object類中的getClass()方法 Person person = new Person(); Class clazz = person.getClass(); 方式二: 通過 類名.class 獲取到字節碼文件對象(任意數據類型都具備一個class靜態屬性,看上去要比第一種方式簡單)。 Class clazz = Person.class; 方式三: 通過Class類中的方法(將類名作為字符串傳遞給Class類中的靜態方法forName即可)。 Class c3 = Class.forName("Person"); 注:第三種和前兩種的區別是: 前兩種你必須明確Person類型. 后面是指定這種類型的字符串就行.這種擴展更強.我不需要知道你的類.我只提供字符串,按照配置文件加載就可以了 * 2. 得到Class對象的三個方法代碼演示: ? 代碼演示 /* * 獲取.class字節碼文件對象的方式 * 1:通過Object類中的getObject()方法 * 2: 通過 類名.class 獲取到字節碼文件對象 * 3: 反射中的方法, * public static Class> forName(String className) throws ClassNotFoundException * 返回與帶有給定字符串名的類或接口相關聯的 Class 對象 */ public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException { // 1: 通過Object類中的getObject()方法 // Person p1 = new Person(); // Class c1 = p1.getClass(); // System.out.println("c1 = "+ c1); // 2: 通過 類名.class 獲取到字節碼文件對象 // Class c2 = Person.class; // System.out.println("c2 = "+ c2); // 3: 反射中的方法 Class c3 = Class.forName("cn.itcast_01_Reflect.Person");// 包名.類名 System.out.println("c3 = " + c3); } }
? Person類
package cn.itcast_01_Reflect; public class Person { //成員變量 public String name; public int age; private String address; //構造方法 public Person() { System.out.println("空參數構造方法"); } public Person(String name) { this.name = name; System.out.println("帶有String的構造方法"); } //私有的構造方法 private Person(String name, int age){ this.name = name; this.age = age; System.out.println("帶有String,int的構造方法"); } public Person(String name, int age, String address){ this.name = name; this.age = age; this.address = address; System.out.println("帶有String, int, String的構造方法"); } //成員方法 //沒有返回值沒有參數的方法 public void method1(){ System.out.println("沒有返回值沒有參數的方法"); } //沒有返回值,有參數的方法 public void method2(String name){ System.out.println("沒有返回值,有參數的方法 name= "+ name); } //有返回值,沒有參數 public int method3(){ System.out.println("有返回值,沒有參數的方法"); return 123; } //有返回值,有參數的方法 public String method4(String name){ System.out.println("有返回值,有參數的方法"); return "哈哈" + name; } //私有方法 private void method5(){ System.out.println("私有方法"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", address=" + address+ "]"; } } * 注: Class類型的唯一性 因為一個.class文件在內存里只生成一個Class對象,所以無論那一種方法得到Class對象,得到的都是同一個對象。 * C.通過反射獲取無參構造方法并使用 * a. 得到無參構造方法 public Constructor>[] getConstructors() 獲取所有的public 修飾的構造方法。 選擇無參構造方法,不建議使用。 public Constructor3總結getConstructor(Class>... parameterTypes) 獲取public修飾, 指定參數類型所對應的構造方法。 不傳參數得到無參構造方法。 * b. 運行無參構造方法 public T newInstance(Object... initargs) 使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,并用指定的初始化參數初始化該實例。 因為是無參構造,所以不傳參數。 * c. 通過反射獲取無參構造方法并使用的代碼演示: package cn.itcast.demo1; import java.lang.reflect.Constructor; /* * 通過反射獲取class文件中的構造方法,運行構造方法 * 運行構造方法,創建對象 * 獲取class文件對象 * 從class文件對象中,獲取需要的成員 * * Constructor 描述構造方法對象類 */ public class ReflectDemo1 { public static void main(String[] args) throws Exception { Class c = Class.forName("cn.itcast.demo1.Person"); //使用class文件對象,獲取類中的構造方法 // Constructor[] getConstructors() 獲取class文件對象中的所有公共的構造方法 /*Constructor[] cons = c.getConstructors(); for(Constructor con : cons){ System.out.println(con); }*/ //獲取指定的構造方法,空參數的構造方法 Constructor con = c.getConstructor(); //運行空參數構造方法,Constructor類方法 newInstance()運行獲取到的構造方法 Object obj = con.newInstance(); System.out.println(obj.toString()); } } * D. 通過反射獲取有參構造方法并使用 * a. 得到有參的構造方法 public Constructor getConstructor(Class>... parameterTypes) 獲取public修飾, 指定參數類型所對應的構造方法。 傳相應的參數類型得到有參構造方法。 * b. 運行無參構造方法 public T newInstance(Object... initargs) 使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,并用指定的初始化參數初始化該實例。 因為是有參構造,所以傳相應的參數值。 * c. 通過反射獲取有參構造方法并使用的代碼演示: package cn.itcast.demo1; import java.lang.reflect.Constructor; /* * 通過反射,獲取有參數的構造方法并運行 * 方法getConstructor,傳遞可以構造方法相對應的參數列表即可 */ public class ReflectDemo2 { public static void main(String[] args)throws Exception { Class c = Class.forName("cn.itcast.demo1.Person"); //獲取帶有,String和int參數的構造方法 //Constructor getConstructor(Class>... parameterTypes) //Class>... parameterTypes 傳遞要獲取的構造方法的參數列表 Constructor con = c.getConstructor(String.class,int.class); //運行構造方法 // T newInstance(Object... initargs) //Object... initargs 運行構造方法后,傳遞的實際參數 Object obj = con.newInstance("張三",20); System.out.println(obj); } } * E. 通過反射獲取有參構造方法并使用快捷方式 * a. 使用的前提 類有空參的公共構造方法。(如果是同包,默認權限也可以) * b. 使用的基礎 Class類的 public T newInstance() 方法 創建此 Class 對象所表示的類的一個新實例。 * c. 通過反射獲取有參構造方法并使用快捷方式的代碼演示: package cn.itcast.demo1; /* * 反射獲取構造方法并運行,有快捷點的方式 * 有前提: * 被反射的類,必須具有空參數構造方法 * 構造方法權限必須public */ public class ReflectDemo3 { public static void main(String[] args) throws Exception { Class c = Class.forName("cn.itcast.demo1.Person"); // Class類中定義方法, T newInstance() 直接創建被反射類的對象實例 Object obj = c.newInstance(); System.out.println(obj); } } * F. 通過反射獲取私有構造方法并使用 * a. 得到私有的構造方法 public Constructor getDeclaredConstructor(Class>... parameterTypes) 獲取指定參數類型所對應的構造方法(包含私有的)。 public Constructor>[] getDeclaredConstructors() 獲取所有的構造方法(包含私有的)。 * b. 運行私有構造方法 public void setAccessible(boolean flag) 將此對象的 accessible 標志設置為指示的布爾值。 設置為true,這個方法保證我們得到的私有構造方法的運行。(取消運行時期的權限檢查。) public T newInstance(Object... initargs) 使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,并用指定的初始化參數初始化該實例。 * c. 通過反射獲取私有構造方法并使用的代碼演示: package cn.itcast.demo1; import java.lang.reflect.Constructor; /* * 反射獲取私有的構造方法運行 * 不推薦,破壞了程序的封裝性,安全性 * 暴力反射 */ public class ReflectDemo4 { public static void main(String[] args) throws Exception{ Class c = Class.forName("cn.itcast.demo1.Person"); //Constructor[] getDeclaredConstructors()獲取所有的構造方法,包括私有的 /*Constructor[] cons = c.getDeclaredConstructors(); for(Constructor con : cons){ System.out.println(con); }*/ //Constructor getDeclaredConstructor(Class...c)獲取到指定參數列表的構造方法 Constructor con = c.getDeclaredConstructor(int.class,String.class); //Constructor類,父類AccessibleObject,定義方法setAccessible(boolean b) con.setAccessible(true); Object obj = con.newInstance(18,"lisi"); System.out.println(obj); } } * 注:不推薦,破壞了程序的封裝性,安全性。 * G. 反射獲取成員變量并改值 * a. 獲取成員變量 * 得到公共的成員變量 public Field getField(String name) 返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。 public Field[] getFields() 返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或接口的所有可訪問公共字段。 * 得到所有的成員變量(包括私有的,如果要進行修改私有成員變量,要先進行public void setAccessible(boolean flag) 設置。) public Field getDeclaredField(String name) 返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。 public Field[] getDeclaredFields() 返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段。 * b. 修改成員變量(Field)的值 * 修改公共的成員變量 public void set(Object obj, Object value) 將指定對象變量上此 Field 對象表示的字段設置為指定的新值。 obj指的是修改的是那個對象的這個成員變量值。 * c. 反射獲取成員變量并改值的代碼演示 package cn.itcast.demo1; import java.lang.reflect.Field; /* * 反射獲取成員變量,并修改值 * Person類中的成員String name */ public class ReflectDemo5 { public static void main(String[] args) throws Exception{ Class c = Class.forName("cn.itcast.demo1.Person"); Object obj = c.newInstance(); //獲取成員變量 Class類的方法 getFields() class文件中的所有公共的成員變量 //返回值是Field[] Field類描述成員變量對象的類 /*Field[] fields = c.getFields(); for(Field f : fields){ System.out.println(f); }*/ //獲取指定的成員變量 String name //Class類的方法 Field getField(傳遞字符串類型的變量名) 獲取指定的成員變量 Field field = c.getField("name"); //Field類的方法 void set(Object obj, Object value) ,修改成員變量的值 //Object obj 必須有對象的支持, Object value 修改后的值 field.set(obj,"王五"); System.out.println(obj); } } * H. 反射獲取空參數成員方法并運行 * a. 獲取空參數成員方法 * 得到公共的成員方法 public Method getMethod(String name, Class>... parameterTypes) 返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。 public Method[] getMethods() 返回一個包含某些 Method 對象的數組,這些對象反映此 Class對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。 * 得到全部的成員方法(包括私有的,如果要使用私有成員方法,要先進行public void setAccessible(boolean flag) 設置。) public Method getDeclaredMethod(String name, Class>... parameterTypes) 返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。 public Method[] getDeclaredMethods() 返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 * b. 使用Method方法對象 public Object invoke(Object obj, Object... args) 對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。 obj 指的是調這個方法的對象。 args 指的是調用這個方法所要用到的參數列表。 返回值Object就是方法的返回對象。如果方法沒有返回值 ,返回的是null. * c. 反射獲取空參數成員方法并運行代碼演示 package cn.itcast.demo1; import java.lang.reflect.Method; /* * 反射獲取成員方法并運行 * public void eat(){} */ public class ReflectDemo6 { public static void main(String[] args) throws Exception{ Class c = Class.forName("cn.itcast.demo1.Person"); Object obj = c.newInstance(); //獲取class對象中的成員方法 // Method[] getMethods()獲取的是class文件中的所有公共成員方法,包括繼承的 // Method類是描述成員方法的對象 /*Method[] methods = c.getMethods(); for(Method m : methods){ System.out.println(m); }*/ //獲取指定的方法eat運行 // Method getMethod(String methodName,Class...c) // methodName獲取的方法名 c 方法的參數列表 Method method = c.getMethod("eat"); //使用Method類中的方法,運行獲取到的方法eat //Object invoke(Object obj, Object...o) method.invoke(obj); } } * I. 反射獲取有參數成員方法并運行 * a. 獲取有參數成員方法 * 得到公共的成員方法 public Method getMethod(String name, Class>... parameterTypes) 返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。 public Method[] getMethods() 返回一個包含某些 Method 對象的數組,這些對象反映此 Class對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。 * 得到全部的成員方法(包括私有的,如果要使用私有成員方法,要先進行public void setAccessible(boolean flag) 設置。) public Method getDeclaredMethod(String name, Class>... parameterTypes) 返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。 public Method[] getDeclaredMethods() 返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 * b. 使用Method方法對象 public Object invoke(Object obj, Object... args) 對帶有指定參數的指定對象調用由此 Method 對象表示的底層方法。 obj 指的是調這個方法的對象。 args 指的是調用這個方法所要用到的參數列表。 返回值Object就是方法的返回對象。如果方法沒有返回值 ,返回的是null. * c. 反射獲取有參數成員方法并運行代碼演示 package cn.itcast.demo1; import java.lang.reflect.Method; /* * 反射獲取有參數的成員方法并執行 * public void sleep(String,int,double){} */ public class ReflectDemo7 { public static void main(String[] args) throws Exception{ Class c = Class.forName("cn.itcast.demo1.Person"); Object obj = c.newInstance(); //調用Class類的方法getMethod獲取指定的方法sleep Method method = c.getMethod("sleep", String.class,int.class,double.class); //調用Method類的方法invoke運行sleep方法 method.invoke(obj, "休眠",100,888.99); } } * J. 反射泛型擦除 * a. 使用情況 例如:在泛型為String的集合里,添加Integer的數據 ArrayList list = new ArrayList (); list.add(100); * b. 能用泛型擦除的理論 偽泛型:在編譯后的.class文件里面是沒有泛型的。類型為Object。 用反射的方法繞過編譯,得到Class文件對象,直接調用add方法。 * c. 反射泛型擦除的代碼演示 package cn.itcast.demo2; import java.lang.reflect.Method; import java.util.ArrayList; /* * 定義集合類,泛型String * 要求向集合中添加Integer類型 * * 反射方式,獲取出集合ArrayList類的class文件對象 * 通過class文件對象,調用add方法 * * 對反射調用方法是否理解 */ public class ReflectTest { public static void main(String[] args)throws Exception { ArrayList array = new ArrayList (); array.add("a"); //反射方式,獲取出集合ArrayList類的class文件對象 Class c = array.getClass(); //獲取ArrayList.class文件中的方法add Method method = c.getMethod("add",Object.class); //使用invoke運行ArrayList方法add method.invoke(array, 150); method.invoke(array, 1500); method.invoke(array, 15000); System.out.println(array); } } * K. 反射通過配置文件來決定運行的步驟 * a. 操作依據 通過配置文件得到類名和要運行的方法名,用反射的操作類名得到對象和調用方法 * b. 實現步驟: * 1. 準備配置文件,鍵值對 * 2. IO流讀取配置文件 Reader * 3. 文件中的鍵值對存儲到集合中 Properties * 集合保存的鍵值對,就是類名和方法名 * 4. 反射獲取指定類的class文件對象 * 5. class文件對象,獲取指定的方法 * 6. 運行方法 * c. 代碼演示 代碼: package cn.itcast.demo3; import java.io.FileReader; import java.lang.reflect.Method; import java.util.Properties; /* * 調用Person方法,調用Student方法,調用Worker方法 * 類不清楚,方法也不清楚 * 通過配置文件實現此功能 * 運行的類名和方法名字,以鍵值對的形式,寫在文本中 * 運行哪個類,讀取配置文件即可 * 實現步驟: * 1. 準備配置文件,鍵值對 * 2. IO流讀取配置文件 Reader * 3. 文件中的鍵值對存儲到集合中 Properties * 集合保存的鍵值對,就是類名和方法名 * 4. 反射獲取指定類的class文件對象 * 5. class文件對象,獲取指定的方法 * 6. 運行方法 */ public class Test { public static void main(String[] args) throws Exception{ //IO流讀取配置文件 FileReader r = new FileReader("config.properties"); //創建集合對象 Properties pro = new Properties(); //調用集合方法load,傳遞流對象 pro.load(r); r.close(); //通過鍵獲取值 String className = pro.getProperty("className"); String methodName = pro.getProperty("methodName"); //反射獲取指定類的class文件對象 Class c = Class.forName(className); Object obj = c.newInstance(); //獲取指定的方法名 Method method = c.getMethod(methodName); method.invoke(obj); } } 配置文件: #className=cn.itcast.demo3.Student #methodName=study className=cn.itcast.demo3.Person methodName=eat #className=cn.itcast.demo3.Worker #methodName=job
把今天的知識點總結一遍。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67178.html
摘要:反射學習的靈魂我們從最初的,到面向對象部分,我們可以將代碼在計算機中經歷的階段分為三部分源代碼階段類對象階段運行時階段而我們知道,中一個類在源代碼階段,是存儲在硬盤中的,而編譯后,就已經被加載到內存中區,那么有沒有一種方法可以在這種情況下 反射:Web學習的靈魂 我們從最初的 javac -HelloWorld.java,到面向對象部分,我們可以將Java代碼在計算機中經歷的階段分為三...
摘要:通過反射獲取帶參無返回值成員方法并使用設置安全檢查,訪問私有構造函數必須創建實例這種不行,注意和方法需要傳遞參數測試復制這個功能獲取私有方法,同樣注意和的區別賦予訪問權限調用方法。 反射 目錄介紹 1.反射概述 1.1 反射概述 1.2 獲取class文件對象的三種方式 1.3 反射常用的方法介紹 1.4 反射的定義 1.5 反射的組成 1.6 反射的作用有哪些 2.反射的...
摘要:分類根類加載器也被稱為引導類加載器,負責核心類的加載比如等。要想解剖一個類必須先要獲取到該類的字節碼文件對象。 這是劉意老師的JAVA基礎教程的筆記講的賊好,附上傳送門 傳智風清揚-超全面的Java基礎 一、類的加載 1.類初始化的時機 創建類的實例訪問類的靜態變量,或者為靜態變量賦值調用類的靜態方法使用反射方式來強制創建某個類或接口對應的java.lang.Class對象初始化某個類...
閱讀 3110·2021-11-24 09:39
閱讀 968·2021-09-07 10:20
閱讀 2389·2021-08-23 09:45
閱讀 2254·2021-08-05 10:00
閱讀 566·2019-08-29 16:36
閱讀 833·2019-08-29 11:12
閱讀 2813·2019-08-26 11:34
閱讀 1839·2019-08-26 10:56