1. 程式人生 > >Android 技能圖譜學習路線系列-Java基礎之反射機制

Android 技能圖譜學習路線系列-Java基礎之反射機制

Java反射機制 一、什麼是反射機制   JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意方法和屬性;這種動態獲取資訊以及動態呼叫物件方法的功能稱為java語言的反射機制。    二、反射機制的作用    在執行時判斷任意一個物件所屬的類;    在執行時構造任意一個類的物件;    在執行時判斷任意一個類所具有的成員變數和方法;    在執行時呼叫任意一個物件的方法;    生成動態代理    三. 反射機制的優點與缺點    反射機制的優點:可以實現動態建立物件和編譯,體現出很大的靈活性(特別是在J2EE的開發中它的靈活性就表現的十分明顯)。通過反射機制我們可以獲得類的各種內容,進行了反編譯。對於JAVA這種先編譯再執行的語言來說,反射機制可以使程式碼更加靈活,更加容易實現面向物件。       反射機制的缺點:使用反射基本上是一種解釋操作,用於欄位和方法接入時要遠慢於直接程式碼。因此Java反射機制只應用在對靈活性和擴充套件性要求很高的系統框架上,普通程式不建議使用。使用反射會模糊程式內部邏輯:程式設計師希望在程式碼中看到程式的邏輯,反射等繞過了原始碼的技術,因而會帶來維護問題。反射程式碼比相應的直接程式碼更復雜。    四. 反射機制的示例 1.通過一個物件獲得完整的包名和類名

所有類的物件其實都是Class的例項。

 1 package Reflect;
 2 
 3 class Demo{
 4     //other codes...
 5 }
 6 
 7 class hello{
 8     public static void main(String[] args) {
 9         Demo demo=new Demo();
10         System.out.println(demo.getClass().getName());
11     }
12 }
13 //【執行結果】:Reflect.Demo

2.例項化Class類物件

 1 package Reflect;
 2 
 3 class Demo{
 4     //other codes...
 5 }
 6 
 7 class hello{
 8     public static void main(String[] args) {
 9         Class<?> demo1=null;
10         Class<?> demo2=null;
11         Class<?> demo3=null;
12         try{
13             //一般儘量採用這種形式
14             demo1=Class.forName("Reflect.Demo");
15         }catch(Exception e){
16             e.printStackTrace();
17         }
18         demo2=new Demo().getClass();
19         demo3=Demo.class;
20 
21         System.out.println("類名稱   "+demo1.getName());
22         System.out.println("類名稱   "+demo2.getName());
23         System.out.println("類名稱   "+demo3.getName());
24     }
25 }
26 //【執行結果】:
27 //類名稱   Reflect.Demo
28 //類名稱   Reflect.Demo
29 //類名稱   Reflect.Demo

3.通過Class例項化其他類的物件

 1 package Reflect;
 2 
 3 class Person{
 4     public String getName() {
 5         return name;
 6     }
 7     public void setName(String name) {
 8         this.name = name;
 9     }
10     public int getAge() {
11         return age;
12     }
13     public void setAge(int age) {
14         this.age = age;
15     }
16     @Override
17     public String toString(){
18         return "["+this.name+"  "+this.age+"]";
19     }
20     private String name;
21     private int age;
22 }
23 
24 class hello{
25     public static void main(String[] args) {
26         Class<?> demo=null;
27         try{
28             demo=Class.forName("Reflect.Person");
29         }catch (Exception e) {
30             e.printStackTrace();
31         }
32         Person per=null;
33         try {
34             per=(Person)demo.newInstance();
35         } catch (InstantiationException e) {
36             // TODO Auto-generated catch block
37             e.printStackTrace();
38         } catch (IllegalAccessException e) {
39             // TODO Auto-generated catch block
40             e.printStackTrace();
41         }
42         per.setName("Rollen");
43         per.setAge(20);
44         System.out.println(per);
45     }
46 }
47 //【執行結果】:
48 //[Rollen  20]

但是注意一下,當我們把Person中的預設的無參建構函式取消的時候,比如自己定義只定義一個有引數的建構函式之後,會出現錯誤:

比如定義了一個建構函式:

1 public Person(String name, int age) {
2         this.age=age;
3         this.name=name;
4     }

然後繼續執行上面的程式,會出現:

java.lang.InstantiationException: Reflect.Person
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at Reflect.hello.main(hello.java:39)
Exception in thread "main" java.lang.NullPointerException
at Reflect.hello.main(hello.java:47)

所以大家以後再編寫使用Class例項化其他類的物件的時候,一定要自己定義無參的建構函式。

4.通過Class呼叫其他類中的建構函式 (也可以通過這種方式通過Class建立其他類的物件)

 1 package Reflect;
 2 
 3 import java.lang.reflect.Constructor;
 4 
 5 class Person{
 6     public Person() {   
 7 
 8     }
 9     public Person(String name){
10         this.name=name;
11     }
12     public Person(int age){
13         this.age=age;
14     }
15     public Person(String name, int age) {
16         this.age=age;
17         this.name=name;
18     }
19     public String getName() {
20         return name;
21     }
22     public int getAge() {
23         return age;
24     }
25     @Override
26     public String toString(){
27         return "["+this.name+"  "+this.age+"]";
28     }
29     private String name;
30     private int age;
31 }
32 
33 class hello{
34     public static void main(String[] args) {
35         Class<?> demo=null;
36         try{
37             demo=Class.forName("Reflect.Person");
38         }catch (Exception e) {
39             e.printStackTrace();
40         }
41         Person per1=null;
42         Person per2=null;
43         Person per3=null;
44         Person per4=null;
45         //取得全部的建構函式
46         Constructor<?> cons[]=demo.getConstructors();
47         try{
48             per1=(Person)cons[0].newInstance();
49             per2=(Person)cons[1].newInstance("Rollen");
50             per3=(Person)cons[2].newInstance(20);
51             per4=(Person)cons[3].newInstance("Rollen",20);
52         }catch(Exception e){
53             e.printStackTrace();
54         }
55         System.out.println(per1);
56         System.out.println(per2);
57         System.out.println(per3);
58         System.out.println(per4);
59     }
60 }
61 //【執行結果】:
62 //[null  0]
63 //[Rollen  0]
64 //[null  20]
65 //[Rollen  20]

5.返回一個類實現的介面

 1 package Reflect;
 2 
 3 interface China{
 4     public static final String name="Rollen";
 5     public static  int age=20;
 6     public void sayChina();
 7     public void sayHello(String name, int age);
 8 }
 9 
10 class Person implements China{
11     public Person() {
12 
13     }
14     public Person(String sex){
15         this.sex=sex;
16     }
17     public String getSex() {
18         return sex;
19     }
20     public void setSex(String sex) {
21         this.sex = sex;
22     }
23     @Override
24     public void sayChina(){
25         System.out.println("hello ,china");
26     }
27     @Override
28     public void sayHello(String name, int age){
29         System.out.println(name+"  "+age);
30     }
31     private String sex;
32 }
33 
34 class hello{
35     public static void main(String[] args) {
36         Class<?> demo=null;
37         try{
38             demo=Class.forName("Reflect.Person");
39         }catch (Exception e) {
40             e.printStackTrace();
41         }
42         //儲存所有的介面
43         Class<?> intes[]=demo.getInterfaces();
44         for (int i = 0; i < intes.length; i++) {
45             System.out.println("實現的介面   "+intes[i].getName());
46         }
47     }
48 }
49 //【執行結果】:
50 //實現的介面   Reflect.China

(以下幾個例子,都會用到這個例子的Person類,所以為節省篇幅,此處不再貼上Person的程式碼部分,只貼上主類hello的程式碼)

6.取得其他類中的父類

 1 class hello{
 2     public static void main(String[] args) {
 3         Class<?> demo=null;
 4         try{
 5             demo=Class.forName("Reflect.Person");
 6         }catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         //取得父類
10         Class<?> temp=demo.getSuperclass();
11         System.out.println("繼承的父類為:   "+temp.getName());
12     }
13 }
14 //【執行結果】
15 //繼承的父類為:   java.lang.Object

7.獲得其他類中的全部建構函式

 1 //這個例子需要在程式開頭新增import java.lang.reflect.*;
 2 class hello{
 3     public static void main(String[] args) {
 4         Class<?> demo=null;
 5         try{
 6             demo=Class.forName("Reflect.Person");
 7         }catch (Exception e) {
 8             e.printStackTrace();
 9         }
10         Constructor<?>cons[]=demo.getConstructors();
11         for (int i = 0; i < cons.length; i++) {
12             System.out.println("構造方法:  "+cons[i]);
13         }
14     }
15 }
16 //【執行結果】:
17 //構造方法:  public Reflect.Person()
18 //構造方法:  public Reflect.Person(java.lang.String)


 1 class hello{
 2     public static void main(String[] args) {
 3         Class<?> demo=null;
 4         try{
 5             demo=Class.forName("Reflect.Person");
 6         }catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         Constructor<?>cons[]=demo.getConstructors();
10         for (int i = 0; i < cons.length; i++) {
11             Class<?> p[]=cons[i].getParameterTypes();
12             System.out.print("構造方法:  ");
13             int mo=cons[i].getModifiers();
14             System.out.print(Modifier.toString(mo)+" ");
15             System.out.print(cons[i].getName());
16             System.out.print("(");
17             for(int j=0;j<p.length;++j){
18                 System.out.print(p[j].getName()+" arg"+i);
19                 if(j<p.length-1){
20                     System.out.print(",");
21                 }
22             }
23             System.out.println("){}");
24         }
25     }
26 }
27 //【執行結果】:
28 //構造方法:  public Reflect.Person(){}
29 //構造方法:  public Reflect.Person(java.lang.String arg1){}

8.取得其他類的全部屬性,將這些整理在一起,也就是通過class取得一個類的全部框架

 1 class hello {
 2     public static void main(String[] args) {
 3         Class<?> demo = null;
 4         try {
 5             demo = Class.forName("Reflect.Person");
 6         } catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         System.out.println("===============本類屬性========================");
10         // 取得本類的全部屬性
11         Field[] field = demo.getDeclaredFields();
12         for (int i = 0; i < field.length; i++) {
13             // 許可權修飾符
14             int mo = field[i].getModifiers();
15             String priv = Modifier.toString(mo);
16             // 屬性型別
17             Class<?> type = field[i].getType();
18             System.out.println(priv + " " + type.getName() + " "
19                     + field[i].getName() + ";");
20         }
21         System.out.println("===============實現的介面或者父類的屬性========================");
22         // 取得實現的介面或者父類的屬性
23         Field[] filed1 = demo.getFields();
24         for (int j = 0; j < filed1.length; j++) {
25             // 許可權修飾符
26             int mo = filed1[j].getModifiers();
27             String priv = Modifier.toString(mo);
28             // 屬性型別
29             Class<?> type = filed1[j].getType();
30             System.out.println(priv + " " + type.getName() + " "
31                     + filed1[j].getName() + ";");
32         }
33     }
34 }
35 //【執行結果】:
36 //===============本類屬性========================
37 //private java.lang.String sex;
38 //===============實現的介面或者父類的屬性========================
39 //public static final java.lang.String name;
40 //public static final int age;

9.通過反射呼叫其他類中的方法

 1 class hello {
 2     public static void main(String[] args) {
 3         Class<?> demo = null;
 4         try {
 5             demo = Class.forName("Reflect.Person");
 6         } catch (Exception e) {
 7             e.printStackTrace();
 8         }
 9         try{
10             //呼叫Person類中的sayChina方法
11             Method method=demo.getMethod("sayChina");
12             method.invoke(demo.newInstance());
13             //呼叫Person的sayHello方法
14             method=demo.getMethod("sayHello", String.class,int.class);
15             method.invoke(demo.newInstance(),"Rollen",20);
16         }catch (Exception e) {
17             e.printStackTrace();
18         }
19     }
20 }
21 //【執行結果】:
22 //hello ,china
23 //Rollen  20

10.呼叫其他類的set和get方法

 1 class hello {
 2     public static void main(String[] args) {
 3         Class<?> demo = null;
 4         Object obj=null;
 5         try {
 6             demo = Class.forName("Reflect.Person");
 7         } catch (Exception e) {
 8             e.printStackTrace();
 9         }
10         try{
11          obj=demo.newInstance();
12         }catch (Exception e) {
13             e.printStackTrace();
14         }
15         setter(obj,"Sex","男",String.class);
16         getter(obj,"Sex");
17     }
18 
19     /**
20      * @param obj   操作的物件
21      * @param att   操作的屬性
22      * */
23     public static void getter(Object obj, String att) {
24         try {
25             Method method = obj.getClass().getMethod("get" + att);
26             System.out.println(method.invoke(obj));
27         } catch (Exception e) {
28             e.printStackTrace();
29         }
30     }
31 
32     /**
33      * @param obj   操作的物件    
34      * @param att   操作的屬性
35      * @param value 設定的值
36      * @param type  引數的屬性
37      * */
38     public static void setter(Object obj, String att, Object value,
39             Class<?> type) {
40         try {
41             Method method = obj.getClass().getMethod("set" + att, type);
42             method.invoke(obj, value);
43         } catch (Exception e) {
44             e.printStackTrace();
45         }
46     }
47 }// end class
48 //【執行結果】:
49 //男

11.通過反射操作屬性

 1 class hello {
 2     public static void main(String[] args) throws Exception {
 3         Class<?> demo = null;
 4         Object obj = null;
 5 
 6         demo = Class.forName("Reflect.Person");
 7         obj = demo.newInstance();
 8 
 9         Field field = demo.getDeclaredField("sex");
10         field.setAccessible(true);
11         field.set(obj, "男");
12         System.out.println(field.get(obj));
13     }
14 }// end class

12.通過反射取得並修改陣列的資訊

 1 import java.lang.reflect.*;
 2 
 3 class hello{
 4     public static void main(String[] args) {
 5         int[] temp={1,2,3,4,5};
 6         Class<?>demo=temp.getClass().getComponentType();
 7         System.out.println("陣列型別: "+demo.getName());
 8         System.out.println("陣列長度  "+Array.getLength(temp));
 9         System.out.println("陣列的第一個元素: "+Array.get(temp, 0));
10         Array.set(temp, 0, 100);
11         System.out.println("修改之後陣列第一個元素為: "+Array.get(temp, 0));
12     }
13 }
14 //【執行結果】:
15 //陣列型別: int
16 //陣列長度  5
17 //陣列的第一個元素: 1
18 //修改之後陣列第一個元素為: 100

13.通過反射修改陣列大小

 1 class hello{
 2     public static void main(String[] args) {
 3         int[] temp={1,2,3,4,5,6,7,8,9};
 4         int[] newTemp=(int[])arrayInc(temp,15);
 5         print(newTemp);
 6         System.out.println("=====================");
 7         String[] atr={"a","b","c"};
 8         String[] str1=(String[])arrayInc(atr,8);
 9         print(str1);
10     }
11     /**
12      * 修改陣列大小
13      * */
14     public static Object arrayInc(Object obj,int len){
15         Class<?>arr=obj.getClass().getComponentType();
16         Object newArr=Array.newInstance(arr, len);
17         int co=Array.getLength(obj);
18         System.arraycopy(obj, 0, newArr, 0, co);
19         return newArr;
20     }
21     /**
22      * 列印
23      * */
24     public static void print(Object obj){
25         Class<?>c=obj.getClass();
26         if(!c.isArray()){
27             return;
28         }
29         System.out.println("陣列長度為: "+Array.getLength(obj));
30         for (int i = 0; i < Array.getLength(obj); i++) {
31             System.out.print(Array.get(obj, i)+" ");
32         }
33     }
34 }
35 //【執行結果】:
36 //陣列長度為: 15
37 //1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
38 //陣列長度為: 8
39 //a b c null null null null null

14.動態代理

首先來看看如何獲得類載入器:

 1 class test{
 2 
 3 }
 4 class hello{
 5     public static void main(String[] args) {
 6         test t=new test();
 7         System.out.println("類載入器  "+t.getClass().getClassLoader().getClass().getName());
 8     }
 9 }
10 //【程式輸出】:
11 //類載入器  sun.misc.Launcher$AppClassLoader

其實在java中有三種類類載入器。

1)Bootstrap ClassLoader 此載入器採用c++編寫,一般開發中很少見。

2)Extension ClassLoader 用來進行擴充套件類的載入,一般對應的是jre\lib\ext目錄中的類

3)AppClassLoader 載入classpath指定的類,是最常用的載入器。同時也是java中預設的載入器。

如果想要完成動態代理,首先需要定義一個InvocationHandler介面的子類,已完成代理的具體操作。

 1 package Reflect;
 2 
 3 import java.lang.reflect.*;
 4 
 5 //定義專案介面
 6 interface Subject {
 7     public String say(String name, int age);
 8 }
 9 
10 // 定義真實專案
11 class RealSubject implements Subject {
12     @Override
13     public String say(String name, int age) {
14         return name + "  " + age;
15     }
16 }
17 
18 class MyInvocationHandler implements InvocationHandler {
19     private Object obj = null;
20 
21     public Object bind(Object obj) {
22         this.obj = obj;
23         return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
24                 .getClass().getInterfaces(), this);
25     }
26 
27     @Override
28     public Object invoke(Object proxy, Method method, Object[] args)
29             throws Throwable {
30         Object temp = method.invoke(this.obj, args);
31         return temp;
32     }
33 }
34 
35 class hello {
36     public static void main(String[] args) {
37         MyInvocationHandler demo = new MyInvocationHandler();
38         Subject sub = (Subject) demo.bind(new RealSubject());
39         String info = sub.say("Rollen", 20);
40         System.out.println(info);
41     }
42 }
43 //【執行結果】:
44 //Rollen  20

類的生命週期

在一個類編譯完成之後,下一步就需要開始使用類,如果要使用一個類,肯定離不開JVM。在程式執行中JVM通過裝載,連結,初始化這3個步驟完成。

類的裝載是通過類載入器完成的,載入器將.class檔案的二進位制檔案裝入JVM的方法區,並且在堆區建立描述這個類的java.lang.Class物件。用來封裝資料。 但是同一個類只會被類裝載器裝載以前

連結就是把二進位制資料組裝為可以執行的狀態。

連結分為校驗,準備,解析這3個階段: 校驗 一般用來確認此二進位制檔案是否適合當前的JVM(版本), 準備 就是為靜態成員分配記憶體空間。並設定預設值 解析 指的是轉換常量池中的程式碼作為直接引用的過程,直到所有的符號引用都可以被執行程式使用(建立完整的對應關係)。

完成之後,型別也就完成了初始化,初始化之後類的物件就可以正常使用了,直到一個物件不再使用之後,將被垃圾回收。釋放空間。當沒有任何引用指向Class物件時就會被解除安裝,結束類的生命週期。