class Persion{
private String name;
private int age;
@Override
public String toString()
{
return name + " --- " + age;
}
}
public class ReflectTest2
{
public static void setProperty(Object obj,String propertyName,Object value)
throws Exception
{
//获得类的class文件对像
Class clazz = obj.getClass();
//获得propertyName字段
Field field = clazz.getDeclaredField(propertyName);
//设置访问权限
field.setAccessible(true);
//给obj对像赋值
field.set(obj, value);
}
public static void main(String[] args) throws Exception
{
Persion p = new Persion();
System.out.println(p);
setProperty(p,"name","刘德华");
setProperty(p,"age",50);
System.out.println(p);
}
}
从上面代码来看,利用反射 不但可以完成具有通用性的功能,而且,还是访问的private型字段,可见反射的好用之处。
class Persion1{
private String name;
private int age;
public void setName(String name){
this.name=name;
}
}
public class ReflectTest3
{
public static void main(String[] args) throws Exception
{
Persion1 p = new Persion1();
//用普通的方法进行赋值操作
long start = System.currentTimeMillis();
for(int i = 0; i < 100000000L; i ++){
p.setName("张三");
}
long end = System.currentTimeMillis();
System.out.println("普通方法赋值1亿次,执行时间: " + (end-start) + "ms");
//利用反射动态赋值
Class clazz = p.getClass();
Method m = clazz.getDeclaredMethod("setName", String.class);
long start1 = System.currentTimeMillis();
for(int i = 0; i < 100000000L; i ++){
m.invoke(p, "张三");
}
long end1 = System.currentTimeMillis();
System.out.println("反射动态赋值1亿次,执行时间: " + (end1-start1) + "ms");
//利用反射禁止访问检查,动态赋值测试
m.setAccessible(true);
long start2 = System.currentTimeMillis();
for(int i = 0; i < 100000000L; i ++){
m.invoke(p, "张三");
}
long end2 = System.currentTimeMillis();
System.out.println("反射取消访问检查,动态赋值1亿次,执行时间: " + (end2-start2) + "ms");
}
}
反射动态赋值1亿次,执行时间: 48561ms
反射取消访问检查,动态赋值1亿次,执行时间: 3043ms
三、反射与泛型
public static void main(String[] args) throws Exception
{
//创建一个List只能接收Integer类型
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(100);
// 以下代码会报错
//list.add("hello");
//下面使用反射来越过泛型检查
Class clazz = list.getClass();
//获得List的add方法,在反射内部接收的都是Object对像
Method add = clazz.getDeclaredMethod("add", Object.class);
//执行add操作
add.invoke(list, "hello");
add.invoke(list, "world");
add.invoke(list, "java se");
System.out.println(list);
}
对于泛型,在编写程序时都是给编译器看的,可以查看class文件的反编译结果,发现是没有泛型的,所以从理论上来说,对于上面的list对像,可以存储任意类型,在反射内部处理中,都是处理的Object类型,所以就有了以上代码。
2. 使用反射来获取泛型信息
class student
{
private Map<String,Integer> score ;
}
public class ReflectTest5
{
public static void main(String[] args) throws Exception
{
Class<student> clazz = student.class;
Field f = clazz.getDeclaredField("score");
//通过getType方法只能获得普通类型
System.out.println("score的类型是:" + f.getType()); //打印Map
//1. 获得f的泛型类型
Type gType = f.getGenericType();
//2.如果gType是泛型类型对像
if(gType instanceof ParameterizedType)
{
ParameterizedType pType = (ParameterizedType)gType;
//获取原始类型
Type rType = pType.getRawType();
System.out.println("原始类型是: " + rType);
//获得泛型类型的泛型参数
Type[] gArgs = pType.getActualTypeArguments();
//打印泛型参数
for(int i=0; i < gArgs.length; i ++)
{
System.out.println("第"+ i +"个泛型类型是:" + gArgs[i]);
}
}
else{
System.out.println("获取泛型信息失败");
}
}
}
Type是java.lang.reflect包下的一个接口,该接口代表所有类型的公共接口,Class是Type接口的实现类。