一、使用反射调用可变参数方法
要把可变参数都当做是其对应的数组类型参数;如 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
}
}
}
结果截图: