很多主流框架都使用了反射技術.像ssh框架都採用兩種技術xml做設定檔+反射技術.
與反射有關的類別包.
java.lang.reflect.*;和java.lang.Class;
Java中所有型別(包含基本型別)都對應一個Class物件,這個Class就是java.lang.Class。即每一個型別,在Class中都有一個Class物件跟它對應.Class 沒有公共構造方法。注意不是沒有,是沒有公共的.
如何取得Class對象
複製代碼代碼如下:
.針對每一個物件.getCalss(),可以得到對應的Class.
.Class.forName(String),String的寫法:包名.類別名稱.就會建立包名.類別名稱對應的那個物件註:1.2只適用於引用型別
.對於基本類型:封裝類別.TYPE代表了對應的基本類型的Class物件.Integer.TYPE對應的是int的Class物件註:3只適用於基本類型
.類型,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 陣列長度可以為0 或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:
[email protected]">寄郵件</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:
[email protected]">寄郵件</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:
[email protected]">寄郵件</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:
[email protected]">寄郵件</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:
[email protected]">寄郵件</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", "[email protected]");
User user = (User)DynamicReflect.getInstance(className, map);
System.out.println(user.getName() + "," + user.getAge() + "," + user.getEmail());
}
}
程式運行結果
複製代碼代碼如下: