Java反射機制探秘


反射主要解決動態編程,即使用反射時,所有的對象生成是動態的,因此調用的方法也是動態的.反射可以簡化開發,但是代碼的可讀性很低.

很多主流框架都使用了反射技術.ssh框架都采用兩種技術 xml做配置文件+反射技術.

 

與反射有關的類包.

java.lang.reflect.*;java.lang.Class;

 

Java中所有類型(包括基本類型)都對應一個Class對象,這個Class就是java.lang.Class。即每一個類型,Class中都有一個Class對象跟它對應.Class 沒有公共構造方法。注意不是沒有,是沒有公共的.

 

如何獲得Class對象

1.針對每一個對象.getCalss(),可以得到對應的Class. 2.Class.forName(String),String的寫法:包名.類名.就會創建包名.類名對應的那個對象 注:1.2只適用於引用類型 3.對於基本類型:封裝類.TYPE代表了對應的基本類型的Class對象.Integer.TYPE對應的是int的Class對象 注:3只適用於基本類型 4.類型,Class。<第4種是通用的.> 上面的4種方法,只有方法2是動態的,只要換一個包就可以了.它具有動態潛質.所以真正意義的想體現動態編程只能使用方法2.

每種類型的Class對象只有一個,即他們的地址只有一個,但是不同類型是不同的.

所以下面的打印結果都為true.

//對與引用類型
Class c1 = "".getClass(); Class c2 =     Class.forName("java.lang.String"); Class c3 = String.class; System.out.println(c1 ==c2);//true //對於基本類型
Class num1 = Integer.TYPE; Class num2 = int.class; System.out.println(num1 == num2);//true

 

反射獲取類中的成員的相關方法

[獲取構造<根據參數類型>](使用時一般用不帶declared)

 Constructor<T> getConstructor(Class<?>... parameterTypes) 返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構造方法。 Constructor<?>[] getConstructors() 返回一個包含某些 Constructor 對象的數組,這些對象反映此 Class 對象所表示的類的所有公共構造方法。 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或接口的指定構造方法。 Constructor<?>[] getDeclaredConstructors() 返回 Constructor 對象的一個數組,這些對象反映此 Class 對象表示的類聲明的所有構造方法。 

[獲取屬性<根據屬性名>](使用時一般用是帶declared,因為屬性一般都是私有的)

 Field getField(String name) 
      返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。 
 Field[] getFields() 
      返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或接口的所有可訪問公共字段。 
 Field getDeclaredField(String name) 
      返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。 
 Field[] getDeclaredFields() 
      返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段。 

[獲取方法<方法名加上參數類型>](使用時一般用不帶declared)

 Method getMethod(String name, Class<?>... parameterTypes) 返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。 Method[] getMethods() 返回一個包含某些 Method 對象的數組,這些對象反映此 Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。 Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。 Method[] getDeclaredMethods() 返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 T newInstance() 創建此 Class 對象所表示的類的一個新實例。 <new Instance()可以動態的創建對象> String toString() 將對象轉換為字符串。 

注意:

new Instance()調用的是無參構造,如果該類沒有無參構造方法,newInstance()會產生異常.

declared的方法是支持私有,但是不支持繼承,declared的方法支持繼承,不支持私有,且只能取出public的東西.

因此取屬性的時候一般來說是帶declared,因為屬性一般都是私有的,取方法時一般是不帶declared,取構造時一般也是不帶declared.

 

實例模擬反射獲取類中的相關屬性和方法

利用反射對屬性賦值

Field中的方法

 Object get(Object obj) 

  返回指定對象上此 Field 表示的字段的值。 

      Field f = c.getXXField(屬性名);

      值 = f.get(對象);

 void set(Object obj, Object value) 

  將指定對象變量上此 Field 對象表示的字段設置為指定的新值。 

  f.set(對象,);

 Class<?> getType() 

  返回一個 Class 對象,它標識了此 Field 對象所表示字段的聲明類型。 

      用於獲取屬性的類型(返回Class對象).

    Class c = Student.class; Object obj = c.newInstance();            //創建Student類的對象
    Field f = c.getDeclaredField("name");        //獲取name屬性
    f.setAccessible(true);                    //設置私有可以訪問.
    f.set(obj, "zhangsan"); System.out.println(f.get(obj)); //獲取obj的name屬性的值.

 

利用反射調用構造

對於構造真正調用是在調用newInstance()方法時.

    Class c = Class.forName("com.clazz.reflect.Student"); Constructor con = c.getConstructor();         //沒有執行構造,
    Object cObj = c.getConstructor().newInstance();//調用無參的構造方法
    Constructor conAll = c.getConstructor(int.class,String.class,int.class); Object caobj = conAll.newInstance(1001,"zjamgs",234235);//調用含參的構造方法.
    System.out.println(caobj);                  //打印輸出

 

利用反射調用方法

對象.方法名(1,2,3);

Method m = c.getMethoed(方法名,參數類型...);

m.invoke(對象,方法調用的參數 )如果底層方法所需的形參數為 0,則所提供的 args 數組長度可以為 或 null

    Class c = Class.forName("com.clazz.reflect.Student"); Object obj = c.newInstance();    //創建Sutdent對象.
    Method msetName = c.getMethod("setName", String.class);//obj無須轉換類型
    msetName.invoke(obj, "zhangsan");//調用方法setName, 並傳參.
    Method msetId = c.getMethod("setId", int.class); msetId.invoke(obj, 409090202); System.out.println(obj);

 

反射應用實例

實體類

package org.dennisit.reflect.entity; import java.io.Serializable; /** * * User.java * * @version : 1.1 * * @author : 蘇若年 <a href="mailto:DennisIT@163.com">發送郵件</a> * * @since : 1.0 創建時間: 2013-2-26 下午01:43:56 * * TODO : class User.java is used for ... * */
public class User implements Serializable{ private String test; public void execute(String name,int age){ System.out.println("name=" + name + ",age=" + age); } }

反射測試類

package org.dennisit.reflect.main; import java.lang.reflect.Field; /** * * ReflectEx.java * * @version : 1.1 * * @author : 蘇若年 <a href="mailto:DennisIT@163.com">發送郵件</a> * * @since : 1.0 創建時間: 2013-2-26 下午01:46:00 * * TODO : class ReflectEx.java is used for ... * */
public class ReflectEx { public static void main(String[] args)throws Exception { Class cls = Class.forName("org.dennisit.reflect.entity.User"); Object obj = cls.newInstance();       //創建User的對象
        Field f = cls.getDeclaredField("test");    //獲取test屬性
        f.setAccessible(true);                    //打開私有屬性test的訪問權限
        f.set(obj, "zhangsan");                    //為test重新復制
        System.out.println(f.get(obj));            //獲取obj的test屬性值 //根據方法名execute獲取方法
        java.lang.reflect.Method m = cls.getMethod("execute", String.class, int.class); m.invoke(obj, "dennisit",23);            //調用execute方法
 } }

運行效果

zhangsan name=dennisit,age=23

 

編寫一個反射動態實例化類的例子

package org.dennisit.reflect.main; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Map; import java.util.Set; /** * * DynamicReflect.java * * @version : 1.1 * * @author : 蘇若年 <a href="mailto:DennisIT@163.com">發送郵件</a> * * @since : 1.0 創建時間: 2013-2-26 下午01:58:12 * * TODO : 利用反射動態實例化的例子 * */
public class DynamicReflect { public static Object getInstance(String className,Map<String,Object> map)throws Exception{ Class c = Class.forName(className); Object obj = c.newInstance();                //對象對象
        Set<String> keys = map.keySet();            //獲取對應的所有屬性
        Field[] fAll = c.getDeclaredFields();        //獲取類中所有屬性
        for(int i=0;i<fAll.length;i++){ for(String key:keys){                    //循環匹配
                if(fAll[i].getName().equals(key)){    //如果用戶傳入的屬性跟獲取到的類中的屬性名匹配
                    Field f = c.getDeclaredField(key);//獲取該屬性 //構建setXxx()方法名
                    String methodName = "set" + key.substring(0,1).toUpperCase()+key.substring(1); Method method = c.getMethod(methodName, f.getType());//根據構建的用戶名獲取對應的方法
                    method.invoke(obj, map.get(key));//方法調用
                }else{ continue; } } } return obj; } }

接下來我們測試我們編寫的動態反射實例化例子

實體類

 

package org.dennisit.reflect.entity; import java.io.Serializable; /** * * User.java * * @version : 1.1 * * @author : 蘇若年 <a href="mailto:DennisIT@163.com">發送郵件</a> * * @since : 1.0 創建時間: 2013-2-26 下午01:43:56 * * TODO : 實體類 * */
public class User implements Serializable{ private String name; private int age; private String email; public User() {  //必須有無參構造
 } //getter() and setter() 
 }

主測試類

package org.dennisit.reflect.main; import java.util.HashMap; import java.util.Map; import org.dennisit.reflect.entity.User; /** * * ReflectEx.java * * @version : 1.1 * * @author : 蘇若年 <a href="mailto:DennisIT@163.com">發送郵件</a> * * @since : 1.0 創建時間: 2013-2-26 下午01:46:00 * * TODO : class ReflectEx.java is used for ... * */
public class ReflectEx { public static void main(String[] args)throws Exception { Class cls = Class.forName("org.dennisit.reflect.entity.User"); String className = "org.dennisit.reflect.entity.User"; Map<String,Object> map = new HashMap<String, Object>(); map.put("name", "dennisit"); map.put("age", 22); map.put("email", "dennisit@163.com"); User user = (User)DynamicReflect.getInstance(className, map); System.out.println(user.getName() + "," + user.getAge() + "," + user.getEmail()); } }

程序運行結果

dennisit,22,dennisit@163.com

 

轉載請注明出處:[http://www.cnblogs.com/dennisit/archive/2013/02/26/2933508.html]

在線交談


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM