1. 程式人生 > >Java學習:反射

Java學習:反射

ade exc 三部曲 通過反射 opened param forname for 步驟

類加載器
(1)什麽是類的加載
當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載,連接,
初始化三步來實現對這個類進行初始化。

一個類在加載過程中的三部曲:
1.加載
就是指將class文件讀入內存,並為之創建一個Class對象.
任何類被使用時系統都會建立一個Class對象。

2.連接
驗證 是否有正確的內部結構,並和其他類協調一致
準備 負責為類的靜態成員分配內存,並設置默認初始化值
解析 將類的二進制數據中的符號引用替換為直接引用

3.初始化 就是我們以前講過的初始化步驟


(2)類的加載時機
2.1 創建類的實例
2.2 訪問類的靜態變量,或者為靜態變量賦值


2.3 調用類的靜態方法
2.4 使用反射方式來強制創建某個類或接口對應的java.lang.Class對象
2.5 初始化某個類的子類
2.6 直接使用java.exe命令來運行某個主類

(3)加載器分類
3.1 類加載起的作用?
負責將.class文件加載到內在中,並為之生成對應的Class對象。

3.2 類加載器的分類
Bootstrap ClassLoader 根類加載器
也被稱為引導類加載器,負責Java核心類的加載
比如System,String等。在JDK中JRE的lib目錄下rt.jar文件中

Extension ClassLoader 擴展類加載器
負責JRE的擴展目錄中jar包的加載。


在JDK中JRE的lib目錄下ext目錄

Sysetm ClassLoader 系統類加載器
負責在JVM啟動時加載來自java命令的class文件

反射
Student.java--Student.class(字節碼文件)--看成一個對象,這個對象就叫字節碼文件對象--對應的類Class
什麽是反射?(畫圖描述)
答:通過字節碼文件對象去使用成員。

(1)獲取字節碼文件對象的三種方式:
A:Object類的getClass()方法
B:數據類型的靜態class屬性
C:Class類的靜態方法forName()
註意:
在平常寫案例的時候,我們直接使用第二種最方便。
但是實際開發中,我們一般用的都是第三種。是因為第三種接收的是一個字符串類型的參數,


我們可以把這個參數作為配置文件的內容進行配置,這樣就實現了一個變化的內容。

技術分享
 1 public static void main(String[] args) throws ClassNotFoundException {
 2         //獲取Person類對應的Class字節碼文件對象
 3         //A:Object類的getClass()方法
 4         Person p1 = new Person();
 5         Person p2 = new Person();
 6         
 7         Class c1 = p1.getClass();
 8         Class c2 = p2.getClass();
 9         System.out.println(p1==p2);//false
10         System.out.println(c1==c2);//true
11         //每一個類會對應一個字節碼文件對象,而這個字節碼文件對象就是這個類的原型,每一個類有且僅有一個字節碼文件對象
12         
13         System.out.println("-------------");
14         //B:數據類型的靜態class屬性
15         Class c3 = Person.class;
16         System.out.println(c2==c3);
17         
18         System.out.println("---------------");
19         //C:Class類的靜態方法forName()
20         //public static Class<?> forName(String className),在這裏所說的類名是全類名(帶包名的類名)
21         //Class c4 = Class.forName("Person");//java.lang.ClassNotFoundException: Person
22         Class c4 = Class.forName("com.edu_01.Person");
23         System.out.println(c3==c4);
24     }
獲取字節碼文件的三種方式


(2)反射的使用步驟
Class:
成員變量 Field
構造方法 Constructor
成員方法 Method

反射:
class字節碼文件對象 -- 去得到對應的成員對象 -- 通過該成員的對象調用方法使用

通過反射獲取構造方法並使用



(3)案例:
1.通過反射獲取構造方法
public Constructor[] getConstructors() 獲取公共的構造方法
public Constructor[] getDeclaredConstructors() 獲取所有的構造方法(包括私有)
public Constructor getConstructor(Class... parameterTypes) 根據構造參數獲取公共的指定構造
public Constructor getDeclaredConstructor(Class<?>... parameterTypes) 根據構造參數獲取指定構造(包括私有,但是私有在使用的時候需要取消訪問限制)

2.通過反射獲取構造方法並創建對象
public T newInstance(Object... initargs)

技術分享
public static void main(String[] args) throws Exception {
        //public Constructor[] getConstructors() 獲取公共的構造方法
        //獲取Peroson類對應的字節碼文件對象
        Class c = Class.forName("com.edu_01.Person");
        
        //獲取Perosn類中對應的構造方法
        Constructor[] cons = c.getConstructors();
        //遍歷所有獲取到的構造方法
        for (Constructor con : cons) {
            System.out.println(con);//public com.edu_01.Person()
        }
        
        System.out.println("----------------");
        //public Constructor[] getDeclaredConstructors() 獲取所有的構造方法(包括私有)
        Constructor[] cons2 = c.getDeclaredConstructors();
        for (Constructor con : cons2) {
            System.out.println(con);
        }
        
        System.out.println("---------------");
        //public Constructor getConstructor(Class... parameterTypes) 根據構造參數獲取公共的指定構造
        //獲取Person類中的公共的無參數的構造方法
        Constructor con  = c.getConstructor();
        System.out.println(con);
        //怎麽通過我們剛才獲取的無參構造創建對象
        //public T newInstance(Object... initargs)
        Object obj = con.newInstance();
        System.out.println(obj);
        
        System.out.println("-------------");
        //獲取Person類中的非公共的構造方法
        //public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
        Constructor con2 = c.getDeclaredConstructor(String.class,int.class,String.class);
        //獲取構造器的時候,傳入的什麽參數,在調用獲取到的這個構造方法對象的時候也就需要傳入什麽類型的參數
        //取消這個構造器對象所對應的訪問權限檢測
        con2.setAccessible(true);
        Object obj2 = con2.newInstance("陳奕迅",45,"香港");
        System.out.println(obj2);
        
        System.out.println("-----------");
        
        //獲取被Protected修飾的構造方法
        Constructor con3 = c.getDeclaredConstructor(String.class,int.class);
        //取消訪問權限的檢測
        con3.setAccessible(true);
        Object obj3 = con3.newInstance("張學友",50);
        System.out.println(obj3);
        
    }
案例1和2

3.通過反射獲取成員變量並使用
public Field[] getFields()獲取公有的成員變量
public Field[] getDeclaredFields()獲取全部的成員變量,包括私有
public Field getDeclaredField(String name) 傳入變量名稱返回指定的成員變量對象,包括私有
public Field getField(String name)傳入變量名稱返回指定的成員變量對象,僅可獲取共有的
public void set(Object obj,Object value)給一個對象的一個字段設置一個值

技術分享
 1 public static void main(String[] args) throws Exception {
 2         //獲取Perosn類對應的字節碼文件對象
 3         Class c = Class.forName("com.edu_01.Person");
 4         
 5         //利用反射獲取一個[Perosn對象
 6         Constructor con = c.getConstructor();
 7         Object obj = con.newInstance();
 8         
 9         //獲取所有公共的字段對象
10         //public Field[] getFields()獲取公有的成員變量
11         Field[] fields = c.getFields();
12         for (Field field : fields) {
13             System.out.println(field);
14         }
15         
16         System.out.println("--------------");
17         //獲取所有的字段對象,包括私有
18         //public Field[] getDeclaredFields()獲取全部的成員變量,包括私有
19         Field[] fields2 = c.getDeclaredFields();
20         for (Field field : fields2) {
21             System.out.println(field);
22         }
23         
24         System.out.println("--------------");
25         //public Field getDeclaredField(String name) 傳入變量名稱返回指定的成員變量對象,包括私有
26         //獲取String name;字段
27         Field f = c.getDeclaredField("name");
28         
29         //使用f這個對象給一個Perosn對象設置姓名
30         //public void set(Object obj, Object value)
31         /**
32          * 參數1:需要設置的對象
33          * 參數2:需要給這個對象設置什麽值
34          */
35         //取消訪問修飾符的限制
36         f.setAccessible(true);
37         f.set(obj, "謝娜");
38         
39         
40         System.out.println("--------------");
41         //public Field getField(String name)傳入變量名稱返回指定的成員變量對象,僅可獲取公有的
42         //獲取public int age;
43         Field f2 = c.getField("age");
44         f2.set(obj, 30);
45         
46         System.out.println("---------------");
47         Field f3 = c.getDeclaredField("address");
48         //取消權限檢測
49         f3.setAccessible(true);
50         f3.set(obj, "湖南");
51         
52         System.out.println(obj);
53         
54         
55     }
案例三

技術分享



4.通過反射獲取成員方法並使用
public Method[] getMethods()獲取所有公共成員方法
public Method[] getDeclaredMethods()獲取所有成員方法,包括私有
public Method getMethod(String name, Class<?>... parameterTypes)參數一:方法名 參數二:方法參數類型.class 獲取指定的公共方法
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)參數一:方法名 參數二:方法參數類型.class 獲取指定的方法,包括私有
Object invoke(Object obj, Object... args) 讓某一個對象使用這個方法,並且傳入參數

技術分享
 1 public static void main(String[] args) throws Exception {
 2         //1.獲取Person類中所有的公有的成員方法
 3         //創建Pwrson類對應的字節碼文件對象
 4         Class c = Class.forName("com.edu_01.Person");
 5         
 6         //利用反射的方式創建一個Person對象
 7         Constructor con  = c.getConstructor();
 8         Object obj = con.newInstance();
 9         
10         //public Method[] getMethods()獲取所有公共成員方法,包括父類的公共的成員方法
11         Method[] methods = c.getMethods();
12         for (Method method : methods) {
13             System.out.println(method);
14         }
15         
16         System.out.println("---------------");
17         //獲取Person類中的所有的成員方法
18         //public Method[] getDeclaredMethods()獲取所有成員方法,包括私有,只能獲取本類的所有的成員方法,不能獲取父類的
19         Method[] methods2 = c.getDeclaredMethods();
20         for (Method method : methods2) {
21             System.out.println(method);
22         }
23         
24         System.out.println("---------------");
25         // public Method getMethod(String name, Class<?>... parameterTypes)
26         //參數一:方法名 參數二:方法參數類型.class 獲取指定的公共方法
27         //獲取method()這個公有的成員方法
28         Method m  = c.getMethod("method");
29         System.out.println(m);
30         
31         System.out.println("---------------");
32         //public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
33         //參數一:方法名 參數二:方法參數類型.class 獲取指定的方法,包括私有
34         //需求獲取method這個個方法
35         Method m2 = c.getDeclaredMethod("method");
36         System.out.println(m2);
37         
38         //使用m2這個成員方法的對象
39         //public Object invoke(Object obj,Object... args)
40         /**
41          * 參數1:執行m2這個方法的對象
42          * 參數2:執行m2這個方法的時候,需要傳入的參數
43          */
44         m2.invoke(obj);
45         
46         System.out.println("-----------------");
47         //獲取Person類中function方法
48         Method m3 = c.getDeclaredMethod("function", int.class);
49         //取消權限檢測
50         m3.setAccessible(true);
51         m3.invoke(obj, 10);
52         
53         System.out.println("-------------------");
54         Method m4 = c.getDeclaredMethod("show", String.class,String.class);
55         m4.setAccessible(true);
56         m4.invoke(obj, "張傑","謝娜");
57         
58     }
案例四

技術分享

Java學習:反射