什么是reflect技术?
网上通常将这种技术称为“反射”,我倒更希望称之为“反映”:从类的底层角度实现来反映一个类的各个部分。
Refect技术能对一个类进行反映,获得类中的成员变量和成员方法。
public class ReflectPoint{
private int x;
public int y;
public String str1="blue";
private String str2="bubble";
public String str3="soso";
publicReflectPoint(int x, int y){
super();
this.x= x;
this.y= y;
}
publicString toString(){
returnstr1+" "+str2+" "+str3;
}
}
比如对于上述的ReflectPoint类,我希望通过对Field变量进行修改,将其中的b字符都修改为a字符。但是显而易见,上述类中并没有提供对应的修改接口,那我们就可以通过reflect技术来处理。
要进行处理,就可以使用reflect技术中的Field抽象;如果使用Field抽象的话,那么我们要做的事:
-
创建一个ReflectPoint实例obj;
-
然后就要获得该类的各个成员变量(Field),获得变量域,首先需要得到Class,所以对应的代码如下:
Field[] fields = obj.getClass().getDeclaredFields(); //此处的declared同时能应付私有和公有;
-
因为要修改的只有string类型,所以要排除int类型的变量;所以此处涉及如何获得field变量的属性:field.getType() == java.lang.string.class;
-
对于字符进行替换,有现成的方法replace();
具备上述要素后,我们就可以进行相应的操作。
实现过程遇到的问题:
-
如果由field获得string对象呢?
只要简单field.get(obj)即可,呵呵。
-
处理后的字符串又如何回填到field对象中呢?
只要field.set(obj, str); 与前述的get相对应。
第一版的实现:
import java.lang.reflect.*;
import java.util.*;
public class MyTest{
publicstatic void main(String args[])
{
ReflectPointrp = new ReflectPoint(5, 9);
changeValue(rp);
System.out.println(rp);
}
staticvoid changeValue(Object obj){
Field[]fields = obj.getClass().getFields();
for(Fieldfield : fields){
try{
if(field.getType()== java.lang.String.class){
Stringstr = (String)field.get(obj);
field.set(obj,str.replace('b', 'a'));
}
}catch(Exceptione){
e.printStackTrace();
}
}
}
}
上述的实现虽然编译和测试通过,但是存在问题:
输出中,只将str1进行修改,而并没有修改str2?原因何在?
难道没有处理str2?
我们可以在代码中插入桩点来测试:的确可以证明str2没有被处理。
那么是什么原因呢?查看下str1和 str2的区别就可以看出来,原来str2是私有的;
那么如何能对私有的数据也处理呢?
Field.setAccessible(true);
但是修改了还是不行,原来在getFields()时,就没有获取私有的对象;所以要获取私有的对象,那么采用的语句:getDeclaredFields();
上述是reflect对于变量的操作,那么如果要对类中的方法进行调用,该如何操作呢?
-
获得方法数组:类似于获得变量数组;
Method [] methods = obj.getClass().getMethods();
-
获得methods对象后,如何执行特定的方法?
可以先获得对象的名字,比如method.getName().equals(“toString”);
String str =(String)method.invoke(object, null);
主要的调用为此;
实践过程中,上述的设计基本没什么问题;代码如下:
staticvoid callMethod(Object obj){
Method[]methods = obj.getClass().getMethods();
for(Methodmethod : methods){
Stringmethodname = method.getName();
if(methodname.equals("toString")){
try{
Objectstr = method.invoke(obj, null);
System.out.println(str);
}catch(Exceptione){
e.printStackTrace();
}
}
}
}