一、使用反射調用可變參數方法
要把可變參數都當做是其對應的數組類型參數;如 show(XX… is)作為 show(XX[] is)調用;
若可變參數元素類型是引用類型:
JDK 内部接收到參數之後,會自動拆包取出參數再配置設定給該底層方法,為此我們需要把這個數組實參先包裝成一個 Object 對象或把實際參數作為一個Object 一維數組的元素再傳遞。
若可變參數元素類型是基本類型:
JDK 内部接收到參數之後,不會拆包,是以可以不必再封裝。不過封裝了也不會錯,是以建議,不管基本類型還是引用類型都使用 Object[]封裝一層,保證無誤。
示例代碼:

import java.lang.reflect.Method;
class VaryMethod {
public static void show(int... args) {
System.out.println("基本資料類型傳遞過來了!");
}
/*public static void show(int[] args){//跟上面的寫法一樣
System.out.println("基本資料類型傳遞過來了!");
}*/
public static void show(String... args) {
System.out.println("引用資料類型傳遞過來了!");
}
}
public class InvokeVaryDemo {
public static void main(String[] args) throws Exception {
Class<VaryMethod> c = VaryMethod.class;
Method m = c.getMethod("show", int[].class);
m.invoke(null, new int[] { 1, 2, 3 });
m = c.getMethod("show", String[].class);
//m.invoke(null,new String[]{"A","B","C"});//ERROR:wrong number of arguments
m.invoke(null, (Object) new String[] { "A", "B", "C" });// 強轉為Object類型
m.invoke(null, new Object[] { new String[] { "A", "B", "C" } });// 推薦寫法
}
}
結果截圖:
二、使用反射操作字段
Field 提供兩組方法操作字段:
xxx getXxx(Object obj):擷取 obj 對象該 Field 的字段值,此處的 xxx 表示 8 個基本資料類型。
若該字段的類型是引用資料類型則使用,Object get(Object obj);
void setXxx(Object obj,xxx val):将 obj 對象的該 Field 字段設定成 val 值,此處的 xxx 表示 8
個基本資料類型。若該字段的類型是引用資料類型則使用,void set(Object obj, Object value);
擷取字元,并且指派,然後再取出來(對應的去檢視api,比如這個是Field,别的比如Constructor,Method)。
步驟:
1.擷取類
2.擷取字段
3.指派(set(c.newInstance(),””));{如果為私有的話設定可接受}
示例代碼:
import java.lang.reflect.Field;
class Cat {
private String name;
public int age;
private String color;
}
public class FieldDemo {
public static void main(String[] args) throws Exception {
Class<Cat> clz = Cat.class;
Field[] f = clz.getDeclaredFields();
for (Field field : f) {
System.out.println(field);
}
Field fi = clz.getDeclaredField("name");
System.out.println(fi);
System.out.println(fi.getName());// name
// 核心開始
/**
* void set(Object obj, Object value) 将指定對象變量上此 Field 對象表示的字段設定為指定的新值。
*/
Cat c = clz.newInstance();
fi.setAccessible(true);
fi.set(c, "劉昭");// 指派成功
Object o = fi.get(c);
System.out.println(o);// 取出成功
fi = clz.getDeclaredField("age");
fi.setAccessible(true);
fi.set(c, 21);
int i = fi.getInt(c);// 左邊的接受類型已經寫成了int,右邊的傳回類型就也必須是int
System.out.println(i);// 擷取成功
}
}
結果截圖:
三、反射和泛型-反射來擷取泛型資訊
通過指定對應的 Class 對象,程式可以獲得該類裡面所有的 Field,不管該 Field 使用 private方法還是public。獲得 Field 對象後都可以使用 getType()來擷取其類型。
Class<?> type = f.getType();//獲得字段的類型
但此方法隻對普通 Field 有效,若該 Field 有泛型修飾,則不能準确得到該 Field 的泛型參數,如
Map<String,Integer>;
為了獲得指定 Field 的泛型類型,我們采用:Type gType = f.getGenericType();得到泛型類型,
然後将 Type 對象強轉為 ParameterizedType,其表示增加泛型後的類型
Type getRawType()//傳回被泛型限制的類型;
Type[] getActualTypeArguments()//傳回泛型參數類型;
利用反射來擷取泛型的類型(泛型資訊)
步驟:
1.擷取目前類
2.擷取目标字段
3.擷取包含泛型類型的類型 getGenericType()
4.強轉至子類 ParameterizedType 因為 Type 沒有任何對應的方法
5.獲得泛型真正的類型 getActualTypeArguments()
示例代碼:
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
public class GetGenericTypeDemo {
Map<String, Integer> map = new HashMap<String, Integer>();
public static void main(String[] args) throws Exception {
Class c = GetGenericTypeDemo.class;
Field f = c.getDeclaredField("map");
System.out.println(f);
System.out.println(f.getName());// map
// Class<?> getType() 傳回一個 Class 對象,它辨別了此 Field 對象 所表示字段的聲明類型。
Class cl = f.getType();
System.out.println("獲得其類型:" + cl);// 獲得其類型:interface java.util.Map
//Type getGenericType() 傳回一個 Type 對象,它表示此 Field 對象 所表示字段的聲明類型。Type是Class的接口;
Type t = f.getGenericType();// 包含泛型的類型
System.out.println(t);// java.util.Map<java.lang.String, java.lang.Integer>
//Type這個類裡面沒有任何的方法,是以需要調用子類的方法,那麼大的類型 轉到小的類型,需要強轉!
ParameterizedType pt = (ParameterizedType) t;// 強轉到其子類
//Type[] getActualTypeArguments() 傳回表示此類型實際類型參數的 Type對象的數組。
//Type getOwnerType() 傳回 Type 對象,表示此類型是其成員之一的類型。
//Type getRawType() 傳回 Type 對象,表示聲明此類型的類或接口。
t = pt.getRawType();// 類型的類或接口
System.out.println(t);
Type[] ts = pt.getActualTypeArguments();
for (Type type : ts) {
System.out.println(type);//class java.lang.String //class java.lang.Integer
}
}
}
結果截圖: