`

实战java反射机制-让你迅速认识java强大的反射机制

    博客分类:
  • java
阅读更多
http://stephen830.iteye.com/blog/256723

Reflection 是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。 (这句话是引用台湾作家侯捷对反射机制描述的一个概念)

java的反射机制从java诞生之日起就成为java的一个重要特性。反射机制也是目前众多框架实现的一个基础。

反射,简单的讲就是根据给出的类的名称,我就可以获得这个类所有的信息(包括属性,构造器,方法等),同时还可以对类的方法进行调用。这在需要动态加载类的情况下尤其显得重要。

目前流行的大部分java框架(例如ssh等)的底层有很多都是基于反射机制来实现的。

从下面的实例中可以了解并学会关于java反射的一些基本特点:
(1)如何获得动态加载类的修饰符,包名,类名,使用的接口,继承的父类
(2)动态获取类的所有属性名,修饰符,属性类型
(3)动态获取所有定义的构造器,构造器使用的参数数量和参数类型
(4)动态获取所有方法,方法的返回值类型,方法名,方法参数数量,方法参数类型
(5)动态调用加载类的方法


下面就从一个例子来深入浅出的认识下java的反射机制:
package com.worthtech.app.util;
/*
 * Created on 2005-6-12
 * Author stephen
 * Email zhoujianqiang AT gmail DOT com
 * CopyRight(C)2005-2008 , All rights reserved.
 */
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * java反射机制的测试类.
 * 
 * @author stephen
 * @version 1.0.0
 */
public class ReflectTest {
	
	/**
	 * 数组参数的标志字符和实际对应的类型.
	 * 其中'L'表示对象数组,其余表示java基础类型的数组.
	 */
	public static final char[]   CODES = new char[]
	{'Z',      'B',   'C',  'L','D',     'F',    'I',   'J',  'S'};
	public static final String[] VALUES =          
	{"boolean","byte","char","","double","float","int","long","short"};
	
	/**
	 * 解析方法的参数.
	 * @param parameter 待解析的参数.
	 * @return
	 */
	public static String parseParameter(String parameter) {
		/* 在java.lang.Class类中关于参数的说明补充
		 * ------------------------------------
		 * Examples:
	     * String.class.getName()
	     *     returns "java.lang.String"
	     * byte.class.getName()
	     *     returns "byte"
	     * (new Object[3]).getClass().getName()
	     *     returns "[Ljava.lang.Object;"
	     * (new int[3][4][5][6][7][8][9]).getClass().getName()
	     *     returns "[[[[[[[I"
	     * ------------------------------------
	     * 1个[表示1维数组,2个[表示2维数组,...,依此类推。
		 */
		boolean isArray = false;
		//如果是数组的可能会在最后带个分号过来,需要去掉.
		if(parameter.charAt(parameter.length()-1)==';'){
			//去掉最后的分号
			parameter = parameter.substring(0,parameter.length()-1);
		}
		while(parameter.indexOf('[')==0){
			isArray = true;
			parameter = parameter.substring(1)+"[]";
		}
		if(isArray){
			char code = parameter.charAt(0);
			for(int i=0;i<CODES.length;i++){
				if(CODES[i]==code){
					parameter=VALUES[i]+parameter.substring(1);
					break;
				}
			}
		}
		return parameter;
	}
	
	/**
	 * 解析属性的类型.
	 * @param parameter 待解析的属性.
	 * @return
	 */
	public static String parseFieldParameter(String parameter) {
		return parseParameter(parameter);
	}
	
	/**
	 * 解析方法返回值的类型.
	 * @param parameter 待解析的方法返回值类型.
	 * @return
	 */
	public static String parseMethodParameter(String parameter) {
		return parseFieldParameter(parameter);
	}
	

	/**
	 * main方法.
	 * @param args
	 */
	public static void main(String[] args) {
		try {
    		StringBuffer debugInfo = new StringBuffer();
    		
    		String className = "java.lang.StringBuffer";//填写要测试的类
			Class c = Class.forName(className);//载入类
			
			debugInfo.append("****************************************\n");
			debugInfo.append("*  "+className+" \n*  通过java反射机制取出的信息"+"\n");
			debugInfo.append("****************************************\n");
			
			//获取包和类名
			Package thePackage = c.getPackage();//获取类的包
			String[] names = c.getName().split("[.]");
			String name = names[names.length-1];
			//获取类的修饰符[如 public final private等等],
			//具体的含义请查看 [java.lang.reflect.Modifier] 中定义的修饰符常量
			//java.lang.String的修饰符是 public final
			int modifiers = c.getModifiers();
			debugInfo.append(Modifier.toString(modifiers)+" class "+ name);
			
			//取出类的父类(extends)
			Class superClass = c.getSuperclass();
			if(superClass!=null && (!"java.lang.Object".equals(superClass.getName()))){
				debugInfo.append(" extends ");
				debugInfo.append(superClass.getName());
			}
			
			//取出类的接口(implements)
			Class[] interfaces = c.getInterfaces();
			if(interfaces!=null && interfaces.length>0){
				debugInfo.append(" implements ");
				for(int i=0;i<interfaces.length;i++){
					if(i>0) debugInfo.append(",");
					debugInfo.append(interfaces[i].getName());
				}
			}
			
			debugInfo.append(" {\n");
			
			//取出所有定义的属性
			debugInfo.append("    //取出所有定义的属性\n");
			Field[] fields = c.getDeclaredFields();
			for(int i=0;fields!=null && i<fields.length;i++){
				//取出属性
				debugInfo.append("    "+Modifier.toString(fields[i].getModifiers())
						+" "+parseFieldParameter(fields[i].getType().getName())
						+" "+fields[i].getName());
				debugInfo.append(";\n");
			}
			
			//获取构造器方法
			debugInfo.append("    //取出所有的构造器方法\n");
			Constructor[] constructors = c.getConstructors();//取出所有定义的构造器方法
			for(int i=0;constructors!=null && i<constructors.length;i++){
				//取出构造器
				debugInfo.append("    "+Modifier.toString(constructors[i].getModifiers())
						+" "+name+"(");
				Class[] parameterTypes = constructors[i].getParameterTypes();
				for(int j=0;parameterTypes!=null&&j<parameterTypes.length;j++){
					if(j>0) debugInfo.append(",");
					debugInfo.append(parseParameter(parameterTypes[j].getName()));//构造器参数
				}
				debugInfo.append("){}\n");
			}
			
			//取出构造器以外的所有方法
			debugInfo.append("    //取出构造器以外的所有方法\n");
			Method[] methods = c.getDeclaredMethods();
			for(int i=0;methods!=null && i<methods.length;i++){
				//取出方法
				debugInfo.append("    "+Modifier.toString(methods[i].getModifiers())+" "
						+ parseMethodParameter(methods[i].getReturnType().getName()) +" "
						+methods[i].getName()+"(");
				Class[] parameterTypes = methods[i].getParameterTypes();
				for(int j=0;parameterTypes!=null&&j<parameterTypes.length;j++){
					if(j>0) debugInfo.append(",");
					debugInfo.append(parseParameter(parameterTypes[j].getName()));//构造器参数
				}
				debugInfo.append("){}\n");
			}
			debugInfo.append("}\n");
			
			System.out.println(debugInfo.toString()+"\n");//输出debug信息
			
			//利用反射机制来调用类中的方法
			//创建一个StringBuffer对象实例 相当于 StringBuffer o = new StringBuffer();
			Object o = c.newInstance();
			//调用方法 o.append(String):认识当参数为对象类型怎么调用的
			Class[] paramTypes = {Class.forName("java.lang.String")};//定义append方法需要的参数
			Object[] values = {new String("hello world")};//定义append方法需要的参数对应的数据
			//调用append(String)方法 相当于 o.append("hello world");
			o.getClass().getMethod("append",paramTypes).invoke(o,values);
			//这里将输出 hello world
			System.out.println("o.append(\""+values[0]+"\").toString()="+o.toString());
			//调用方法 o.append(int):认识当参数为int,float,double,char,boolean等基础类型时候怎么调用的
			paramTypes = new Class[]{int.class};
			values = new Object[]{new Integer(100)};
			o.getClass().getMethod("append",paramTypes).invoke(o,values);
			//这里将输出 hello world100
			System.out.println("o.append(\""+values[0]+"\").toString()="+o.toString());
			
			
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}


除了例子中给出的一些用法,其实通过java反射还可以进行更多的事情,有兴趣的朋友可以自己再深入研究下。

如果你要更好的理解一些框架(例如ssh等)的结构,那么你更加需要好好的研究下这个反射机制。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics