假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。
下面举一个简单的例子,假如有A和B两个程序员,程序员A写出了如下类:
public class ReflectString{
public String str1="Congratulations";
public String str2="you are admitted";
public
String str3="to heima";
}
程序员B的任务是把ReflectString中所有字符串的字母“a”换成字母“g”,当程序员A完成ReflectString类时,程序员B的任务是轻而易举的。可是,假设程序员A由于某种原因并没有完成ReflectString类的编写,那么程序员B应该如何完成任务呢?
答案是反射!
程序员B的代码如下:
private void changeStringValue(Object obj) throw Exception{
Field[] fields=obj.getClass().getFields();
for(Field field:fields){
if(field.getType()==String.class){
String oldValue=(String)field.get(obj);
String newValue=oldValue.replace('b','a');
field.set(obj,newValue);
}
}
}
//反射机制获取Student类的一个Class实例
Class c=Class.forName("com.cwg.reflect.field.Student");
// Class c=Student.class;
// Class c=new Student().getClass();
//下面两种实例化方式二选一
// Student s=(Student)c.newInstance();
Student s=new Student();
//暴力获取private的属性
// Field ff=c.getField("x");//只能获取public的属性
Field fp=c.getDeclaredField("sname"); //获取任意一个声明过的属性,无论private还是public
fp.setAccessible(true);
System.out.println(fp.get(s));
//暴力修改final属性..static修饰的属性值不能被修改
Field ff=c.getDeclaredField("x");
ff.setAccessible(true);
ff.set(s,200);
System.out.println(ff.get(s));
//获取所有属性
Field[] fields = c.getDeclaredFields();
fields[0].setAccessible(true);
fields[0].set(s, "Tom");
System.out.println(s.getSname());
//获取所有方法
Method[] methods=c.getDeclaredMethods();
//调用共有方法
methods[1].invoke(s, "Jeck");
System.out.println(methods[0].invoke(s, null));
//调用私有方法
methods[4].setAccessible(true);
methods[4].invoke(s, "Hello World");
其中第四种方法最长使用:
主要有:
a.配置文件创建form对象。并初始化。
1、使用配置文件产生类的实例。通过配置文件中提供的名称生成类的实例。
2、使用类的实例,根据request中的参数生成一个properties文件,之后使用beanUtils.populte(form,pro);
对form的属性进行复制,其中就是使用reflect方法。
b.当你不知道要创建什么类型的对象时,使用在运行时提供类的完整路径的方式来生成类的实例时,
例如:
在struts中对messageResources引用的生成中,使用到工厂方法的模式,对于他所要使用的工厂,他采用的是factoryClass参数来生成工厂,之后使用这个工厂的实例来生成messageResources对象。
这其中就使用到了使用reflect产生类的实例。
c.当对象的方法只有在运行时才知道那些方法被调用,那些方法不用调用时,且方法遵循一定的规律生成,而且方法很对,比如100个。
例如:
使用日历生成客户经理的月报时,因为一个月是1到31天(最长),我们通过在数据库中配置客户经理日历的表,其中有
customerid,customercode,no1,no2,no3,no4,no5------,no31,remark,tag,status .......
生成的bean和上面的表的字段相对性,如customerbean
我们通过jdbc从数据库查询得到客户经理每个月的数据,通过画表格的方式生成客户经理月报,输出每天的记录时,调用bean的1-31天的方法,如果不采用reflect那么将会是恼人的代码,采用reflect则会节省很多的时间和空间,
d.最有用的也是最经常使用的,通过回调的方式从resultset中查询数据,查询字段和类型的内容是动态的,查询的sql也是动态的即结果集是动态的。这时我们可以很好的使用反射机制。通过指定的字段和类型,使用反射的方法在结果集中查找,并封装成map传回。
反射跟常规调用的主要差异,是反射可以不需要定义接口。
只需要直接约定一个函数即可,比如:
public void instanceService(Object callbackHandler, String methodName) {
调用时则:
Method m = callbackHandler.getClass().getDeclaredMethod(methodName);
m.invoke(callbackHandler);
另一种方式则是直接传递回调的类名和函数名,但比较少用,因为这样做的话,回调主体不明确:
下面举一个简单的例子,假如有A和B两个程序员,程序员A写出了如下类:
public class ReflectString{
public String str1="Congratulations";
public String str2="you are admitted";
public
String str3="to heima";
}
程序员B的任务是把ReflectString中所有字符串的字母“a”换成字母“g”,当程序员A完成ReflectString类时,程序员B的任务是轻而易举的。可是,假设程序员A由于某种原因并没有完成ReflectString类的编写,那么程序员B应该如何完成任务呢?
答案是反射!
程序员B的代码如下:
private void changeStringValue(Object obj) throw Exception{
Field[] fields=obj.getClass().getFields();
for(Field field:fields){
if(field.getType()==String.class){
String oldValue=(String)field.get(obj);
String newValue=oldValue.replace('b','a');
field.set(obj,newValue);
}
}
}
//反射机制获取Student类的一个Class实例
Class c=Class.forName("com.cwg.reflect.field.Student");
// Class c=Student.class;
// Class c=new Student().getClass();
//下面两种实例化方式二选一
// Student s=(Student)c.newInstance();
Student s=new Student();
//暴力获取private的属性
// Field ff=c.getField("x");//只能获取public的属性
Field fp=c.getDeclaredField("sname"); //获取任意一个声明过的属性,无论private还是public
fp.setAccessible(true);
System.out.println(fp.get(s));
//暴力修改final属性..static修饰的属性值不能被修改
Field ff=c.getDeclaredField("x");
ff.setAccessible(true);
ff.set(s,200);
System.out.println(ff.get(s));
//获取所有属性
Field[] fields = c.getDeclaredFields();
fields[0].setAccessible(true);
fields[0].set(s, "Tom");
System.out.println(s.getSname());
//获取所有方法
Method[] methods=c.getDeclaredMethods();
//调用共有方法
methods[1].invoke(s, "Jeck");
System.out.println(methods[0].invoke(s, null));
//调用私有方法
methods[4].setAccessible(true);
methods[4].invoke(s, "Hello World");
其中第四种方法最长使用:
主要有:
a.配置文件创建form对象。并初始化。
1、使用配置文件产生类的实例。通过配置文件中提供的名称生成类的实例。
2、使用类的实例,根据request中的参数生成一个properties文件,之后使用beanUtils.populte(form,pro);
对form的属性进行复制,其中就是使用reflect方法。
b.当你不知道要创建什么类型的对象时,使用在运行时提供类的完整路径的方式来生成类的实例时,
例如:
在struts中对messageResources引用的生成中,使用到工厂方法的模式,对于他所要使用的工厂,他采用的是factoryClass参数来生成工厂,之后使用这个工厂的实例来生成messageResources对象。
这其中就使用到了使用reflect产生类的实例。
c.当对象的方法只有在运行时才知道那些方法被调用,那些方法不用调用时,且方法遵循一定的规律生成,而且方法很对,比如100个。
例如:
使用日历生成客户经理的月报时,因为一个月是1到31天(最长),我们通过在数据库中配置客户经理日历的表,其中有
customerid,customercode,no1,no2,no3,no4,no5------,no31,remark,tag,status .......
生成的bean和上面的表的字段相对性,如customerbean
我们通过jdbc从数据库查询得到客户经理每个月的数据,通过画表格的方式生成客户经理月报,输出每天的记录时,调用bean的1-31天的方法,如果不采用reflect那么将会是恼人的代码,采用reflect则会节省很多的时间和空间,
d.最有用的也是最经常使用的,通过回调的方式从resultset中查询数据,查询字段和类型的内容是动态的,查询的sql也是动态的即结果集是动态的。这时我们可以很好的使用反射机制。通过指定的字段和类型,使用反射的方法在结果集中查找,并封装成map传回。
反射跟常规调用的主要差异,是反射可以不需要定义接口。
只需要直接约定一个函数即可,比如:
public void instanceService(Object callbackHandler, String methodName) {
调用时则:
Method m = callbackHandler.getClass().getDeclaredMethod(methodName);
m.invoke(callbackHandler);
另一种方式则是直接传递回调的类名和函数名,但比较少用,因为这样做的话,回调主体不明确:
public void instanceService(String callbackClass, String methodName) {
例子
Student类
public class Student {
private final String h="hello";
private String sname;
private int age=0;
public String getSname() {
return sname;
}
public int getAge() {
return this.age;
}
public String getH() {
return h;
}
}
测试类
public class MainFanshe {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Student stu=null;
try {
Class c=Class.forName("com.wdf.fanshe.Student");
stu=(Student) c.newInstance();
Field f=c.getDeclaredField("sname");
f.setAccessible(true);
f.set(stu, "tommy");
System.out.println("sname="+stu.getSname());
Field f1=c.getDeclaredField("h");
f1.setAccessible(true);
f1.set(stu, "word");
System.out.println("h="+f1.get(stu));
Field[] fs=c.getDeclaredFields();
fs[2].setAccessible(true);
fs[2].set(stu, 200);
System.out.println("age="+stu.getAge());
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Student stu1=new Student();
Class c1=stu1.getClass();
Method[] ms=c1.getDeclaredMethods();
for(Method m:ms){
System.out.println(m.getName());
}
}
}