java 反射机制 / 反射new 对象 / 反射方式调用方法

java 反射

package test.java;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.net.URL;
/**
 * 
 * @author jalo
 * @printout
 * 反射:通过反射的api 接口,去探索一个运行期间的class 的内部结构,并且根据内部结构,决定方法怎么样去调用。反射可以在运行期间动态的加载
       一个类进来,动态的new 一个对象出来,动态去了解这个对象内部的结构,动态的去调用这个对象的某一个方法
        好处是,配置文件里别的不用写,就写类的名字,就可以动态的把这个类加载进来。加载进来好处:spring / struts / hibernate 很多时候
        类的名字是需要配置在配置文件里的,要用类的对象,就通过反射机制new 出来。以下介绍了反射的5个作用,通过反射,可以了解这个类的方方面面,很
        类似于反汇编,但是反射机制还是看不到类的具体实现。
 *
 */
public class TestReflection {
	
	public static void main(String[] args) {
		
		String ClassName = "test.java.TT";//类的名字,可以配置在properties 文件
		try {
			Class cs = Class.forName(ClassName);//用classLoader 把类load 进来,只是这个函数在Class 类里
			Object obj = cs.newInstance(); //反射1:new 一个对象,但是只能用Object 接收
			
		       	TT obj = (TT)cs.newInstance(); //这里可以用类TT 强转,而后通过obj 点的方式直接调用函数,但是TT 这个类名现在
			System.out.println(obj.getS());<span style="font-family: Arial, Helvetica, sans-serif;">//根本不知道,所以这三行代码不能用,只能用下面的反射invoke 方式调用类TT 的函数</span>
			obj.beReflectCalled("eee", "ggg"); 
			
			System.out.print("new 出来的对象是否是类test.java.TT 的对象 ");
			System.out.println(obj instanceof test.java.TT);//true
			//反射2:动态知道这个加载进来的类的方法    
			for(Method method : cs.getMethods())//如上所述,这里Object类的对象obj 无法调用TT类自己的函数,所以只能用反射方式拿到方法,在去调用
			{
				System.out.println("加载进来的类的方法为: "+method.getName());
				if(method.getName().equals("beReflectCalled")){
					Class returnType = method.getReturnType();//反射3:得到方法的返回类型
					System.out.println("beReflectCalled()返回类型为" + returnType);
					Class [] methodParams = method.getParameterTypes();//反射4:能得到方法的参数
					for(Class methodParam : methodParams)  
						System.out.println("beReflectCalled()参数类型为:  "+methodParam.getName());//两个参数为 class java.lang.String \n class java.lang.String
					//反射5: new出来的TT 类对象,调用beReflectCalled()函数。public Object invoke(Object obj,Object... args),
					//invoke 是可变参数的方法,这个意思是后面这个参数,可以传0个或多个变量做参数
					if(methodParams.length==2 && methodParams[0].getName().equals("java.lang.String")
							&& methodParams[1].getName().equals("java.lang.String")){
						System.out.print("参数验证通过,beReflectCalled()调用成功,调用结果为:");method.invoke(obj, "aaa","bbb"); 
					}
				}
			}  
			//反射2.5 如果已知方法名,可以这种方式调用方法,Method isEvenMethod = compareFuncClass.getMethod("isEven", int.class)
	        	//但是注意第二个参数是Class, 而int 等基本类型也可以直接点class 对象的方式调用class 属性       
        
			//反射6:动态知道这个加载进来的类的成员变量
			for(Field field : cs.getFields())
				System.out.println("类的成员变量为: " + field.getName()); // i , s
		} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}

}

class TT{
	static {
		System.out.println("forName() 一加载,就调用这个static 块");//forName() 一加载,就调用这个static 块
	}
	
	public TT(){
		System.out.println("newInstance()一运行,就调用构造函数");//newInstance()一运行,就调用构造函数
	}
	
	public int i ;
	public String s ;
	
	public void m1(int i){
		this.i = i;
	}
	
	public String getS(){
		return s ;
	}
	
	public void beReflectCalled(String param,String param1){
		System.out.println("be Reflect Called "+param+param1);
	}
}










执行结果为:

forName() 一加载,就调用这个static 块
newInstance()一运行,就调用构造函数
new 出来的对象是否是类test.java.TT 的对象 true
加载进来的类的方法为: m1
加载进来的类的方法为: getS
加载进来的类的方法为: beReflectCalled
beReflectCalled()返回类型为void
beReflectCalled()参数类型为:  java.lang.String
beReflectCalled()参数类型为:  java.lang.String
参数验证通过,beReflectCalled()调用成功,调用结果为:be Reflect Called aaabbb
加载进来的类的方法为: wait
加载进来的类的方法为: wait
加载进来的类的方法为: wait
加载进来的类的方法为: equals
加载进来的类的方法为: toString
加载进来的类的方法为: hashCode
加载进来的类的方法为: getClass
加载进来的类的方法为: notify
加载进来的类的方法为: notifyAll
类的成员变量为: i
类的成员变量为: s


反射作用扩展:

代码模板如下:

   接口  引用 = new 类( );  //  这个用反射机制使其做到可配置

    类 . 方法( );   //  知道了接口名,就知道了方法名和参数,所以这个可以写死。

我一改类还要改第一行代码,如果第一行直接用反射把这个类用new 出来,类名写成可配置的(像上面main 函数中的前三句代码那样),这样如果每次修改需要new 的类,直接通过改配置,替换配置文件中的类名即可,下面的函数调用整个都不需要改。  

这样使程序的可扩展性大大增强。参考:java 接口引用指向对象 / 工厂模式





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值