1. 程式人生 > >java反射例子詳解

java反射例子詳解

1、通過一個物件獲得完整的包名和類名

Java程式碼  收藏程式碼
  1. package Reflect;  
  2. /** 
  3.  * 通過一個物件獲得完整的包名和類名 
  4.  * */
  5. class Demo{  
  6.     //other codes...
  7. }  
  8. class hello{  
  9.     publicstaticvoid main(String[] args) {  
  10.         Demo demo=new Demo();  
  11.         System.out.println(demo.getClass().getName());  
  12.     }  
  13. }  

【執行結果】:Reflect.Demo
新增一句:所有類的物件其實都是Class的例項。


2、例項化Class類物件

Java程式碼  收藏程式碼
  1. package Reflect;  
  2. class Demo{  
  3.     //other codes...
  4. }  
  5. class hello{  
  6.     publicstaticvoid main(String[] args) {  
  7.         Class<?> demo1=null;  
  8.         Class<?> demo2=null;  
  9.         Class<?> demo3=null;  
  10.         try{  
  11.             //一般儘量採用這種形式
  12.             demo1=Class.forName("Reflect.Demo"
    );  
  13.         }catch(Exception e){  
  14.             e.printStackTrace();  
  15.         }  
  16.         demo2=new Demo().getClass();  
  17.         demo3=Demo.class;  
  18.         System.out.println("類名稱   "+demo1.getName());  
  19.         System.out.println("類名稱   "+demo2.getName());  
  20.         System.out.println("類名稱   "+demo3.getName());  
  21.     }  
  22. }  

 【執行結果】:

類名稱   Reflect.Demo

類名稱   Reflect.Demo

類名稱   Reflect.Demo

3、通過Class例項化其他類的物件
    通過無參構造例項化物件

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

 【執行結果】:

[Rollen  20]

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

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

Java程式碼  收藏程式碼
  1. public Person(String name, int age) {  
  2.         this.age=age;  
  3.         this.name=name;  
  4.     }  

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

Java程式碼  收藏程式碼
  1. java.lang.InstantiationException: Reflect.Person  
  2.     at java.lang.Class.newInstance0(Class.java:340)  
  3.     at java.lang.Class.newInstance(Class.java:308)  
  4.     at Reflect.hello.main(hello.java:39)  
  5. Exception in thread "main" java.lang.NullPointerException  
  6.     at Reflect.hello.main(hello.java:47)  

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

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

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

 【執行結果】:

[null  0]

[Rollen  0]

[null  20]

[Rollen  20]

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

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

 【執行結果】:

實現的介面   Reflect.China

6、取得其他類中的父類

Java程式碼  收藏程式碼
  1. class hello{  
  2.     publicstaticvoid 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. }  

 【執行結果】

繼承的父類為:   java.lang.Object

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

Java程式碼  收藏程式碼
  1. class hello{  
  2.     publicstaticvoid 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.             System.out.println("構造方法:  "+cons[i]);  
  12.         }  
  13.     }  
  14. }  

 【執行結果】:

構造方法:  public Reflect.Person()

構造方法:  public Reflect.Person(java.lang.String)

但是細心的讀者會發現,上面的建構函式沒有public 或者private這一類的修飾符

下面這個例子我們就來獲取修飾符

Java程式碼  收藏程式碼
  1. class hello{  
  2.     publicstaticvoid 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. }  

 【執行結果】:

構造方法:  public Reflect.Person(){}

構造方法:  public Reflect.Person(java.lang.String arg1){}

有時候一個方法可能還有異常,呵呵。下面看看:

Java程式碼  收藏程式碼
  1. class hello{  
  2.     publicstaticvoid main(String[] args) {  
  3.         Class<?> demo=null;  
  4.         try{  
  5.             demo=Class.forName("Reflect.Person");  
  6.         }catch (Exception e) {  
  7.             e.printStackTrace();  
  8.         }  
  9.         Method method[]=demo.getMethods();  
  10.         for(int i=0;i<method.length;++i){  
  11.             Class<?> returnType=method[i].getReturnType();  
  12.             Class<?> para[]=method[i].getParameterTypes();  
  13.             int temp=method[i].getModifiers();  
  14.             System.out.print(Modifier.toString(temp)+" ");  
  15.             System.out.print(returnType.getName()+"  ");  
  16.             System.out.print(method[i].getName()+" ");  
  17.             System.out.print("(");  
  18.             for(int j=0;j<para.length;++j){  
  19.                 System.out.print(para[j].getName()+" "+"arg"+j);  
  20.                 if(j<para.length-1){  
  21.                     System.out.print(",");  
  22.                 }  
  23.             }  
  24.             Class<?> exce[]=method[i].getExceptionTypes();  
  25.             if(exce.length>0){  
  26.                 System.out.print(") throws ");  
  27.                 for(int k=0;k<exce.length;++k){  
  28.                     System.out.print(exce[k].getName()+" ");  
  29.                     if(k<exce.length-1){  
  30.                         System.out.print(",");  
  31.                     }  
  32.                 }  
  33.             }else{  
  34.                 System.out.print(")");  
  35.             }  
  36.             System.out.println();  
  37.         }  
  38.     }  
  39. }  

 【執行結果】:

public java.lang.String  getSex ()

public void  setSex (java.lang.String arg0)

public void  sayChina ()

public void  sayHello (java.lang.String arg0,int arg1)

public final native void  wait (long arg0) throws java.lang.InterruptedException

public final void  wait () throws java.lang.InterruptedException

public final void  wait (long arg0,int arg1) throws java.lang.InterruptedException

public boolean  equals (java.lang.Object arg0)

public java.lang.String  toString ()

public native int  hashCode ()

public final native java.lang.Class  getClass ()

public final native void  notify ()

public final native void  notifyAll ()


8、接下來讓我們取得其他類的全部屬性吧,最後我講這些整理在一起,也就是通過class取得一個類的全部框架

Java程式碼  收藏程式碼
  1. class hello {  
  2.     publicstaticvoid 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. }  

【執行結果】:

===============本類屬性========================

private java.lang.String sex;

===============實現的介面或者父類的屬性========================

public static final java.lang.String name;

public static final int age;

【案例】其實還可以通過反射呼叫其他類中的方法:

Java程式碼  收藏程式碼
  1. class hello {  
  2.     publicstaticvoid 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. }  

  【執行結果】:

hello ,china

Rollen  20

9、呼叫其他類的set和get方法

Java程式碼  收藏程式碼
  1. class hello {  
  2.     publicstaticvoid 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.      * @param obj 
  20.      *            操作的物件 
  21.      * @param att 
  22.      *            操作的屬性 
  23.      * */
  24.     publicstaticvoid getter(Object obj, String att) {  
  25.         try {  
  26.             Method method = obj.getClass().getMethod("get" + att);  
  27.             System.out.println(method.invoke(obj));  
  28.         } catch (Exception e) {  
  29.             e.printStackTrace();  
  30.         }  
  31.     }  
  32.     /** 
  33.      * @param obj 
  34.      *            操作的物件 
  35.      * @param att 
  36.      *            操作的屬性 
  37.      * @param value 
  38.      *            設定的值 
  39.      * @param type 
  40.      *            引數的屬性 
  41.      * */
  42.     publicstaticvoid setter(Object obj, String att, Object value,  
  43.             Class<?> type) {  
  44.         try {  
  45.             Method method = obj.getClass().getMethod("set" + att, type);  
  46.             method.invoke(obj, value);  
  47.         } catch (Exception e) {  
  48.             e.printStackTrace();  
  49.         }  
  50.     }  
  51. }// end class

【執行結果】:




10、通過反射操作屬性

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

 11、通過反射取得並修改陣列的資訊:

Java程式碼  收藏程式碼
  1. import java.lang.reflect.*;  
  2. class hello{  
  3.     publicstaticvoid main(String[] args) {  
  4.         int[] temp={1,2,3,4,5};  
  5.         Class<?>demo=temp.getClass().getComponentType();  
  6.         System.out.println("陣列型別: "+demo.getName());  
  7.         System.out.println("陣列長度  "+Array.getLength(temp));  
  8.         System.out.println("陣列的第一個元素: "+Array.get(temp, 0));  
  9.         Array.set(temp, 0100);  
  10.         System.out.println("修改之後陣列第一個元素為: "+Array.get(temp, 0));  
  11.     }  
  12. }  

 【執行結果】:

陣列型別: int

陣列長度  5

陣列的第一個元素: 1

修改之後陣列第一個元素為: 100

12、通過反射修改陣列大小

Java程式碼  收藏程式碼
  1. class hello{  
  2.     publicstaticvoid 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.     publicstatic 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.     publicstaticvoid 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. }  

 【執行結果】:
陣列長度為: 15

1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================

陣列長度為: 8

a b c null null null null null

13、動態代理
   如何獲得類載入器:

Java程式碼  收藏程式碼
  1. class test{  
  2. }  
  3. class hello{  
  4.     publicstaticvoid main(String[] args) {  
  5.         test t=new test();  
  6.         System.out.println("類載入器  "+t.getClass().getClassLoader().getClass().getName());  
  7.     }  
  8. }  

 【程式輸出】:

類載入器  sun.misc.Launcher$AppClassLoader

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

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

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

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

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

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

 【執行結果】:

Rollen  20

類的生命週期

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

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

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



連結分為校驗,準備,解析這3個階段

校驗一般用來確認此二進位制檔案是否適合當前的JVM(版本),

準備就是為靜態成員分配記憶體空間,。並設定預設值

解析指的是轉換常量池中的程式碼作為直接引用的過程,直到所有的符號引用都可以被執行程式使用(建立完整的對應關係)

完成之後,型別也就完成了初始化,初始化之後類的物件就可以正常使用了,直到一個物件不再使用之後,將被垃圾回收。釋放空間。

當沒有任何引用指向Class物件時就會被解除安裝,結束類的生命週期


14、將反射用於工廠模式

  如果不用反射的時候,的工廠模式吧:

Java程式碼  收藏程式碼
  1. /** 
  2.  * @author Rollen-Holt 設計模式之 工廠模式 
  3.  */
  4. interface fruit{  
  5.     publicabstractvoid eat();  
  6. }  
  7. class Apple implements fruit{  
  8.     publicvoid eat(){  
  9.         System.out.println("Apple");  
  10.     }  
  11. }  
  12. class Orange implements fruit{  
  13.     publicvoid eat(){  
  14.         System.out.println("Orange");  
  15.     }  
  16. }  
  17. // 構造工廠類
  18. // 也就是說以後如果我們在新增其他的例項的時候只需要修改工廠類就行了
  19. class Factory{  
  20.     publicstatic fruit getInstance(String fruitName){  
  21.         fruit f=null;  
  22.         if("Apple".equals(fruitName)){  
  23.             f=new Apple();  
  24.         }  
  25.         if("Orange".equals(fruitName)){  
  26.             f=new Orange();  
  27.         }  
  28.         return f;  
  29.     }  
  30. }  
  31. class hello{  
  32.     publicstaticvoid main(String[] a){  
  33.         fruit f=Factory.getInstance("Orange");  
  34.         f.eat();  
  35.     }