Java 反射机制

假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用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);



另一种方式则是直接传递回调的类名和函数名,但比较少用,因为这样做的话,回调主体不明确:

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());
		}
	}

}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值