这两天把JAVA的反射机制看了一遍,回味真的很酸爽,应该说很痴迷和很敬佩JAVA设计者的睿智,太完美了,简直是对C++设计者的一种藐视(原理我的无知,我只是想表达下JAVA的反射有多么强大和完美)。首先定义一下什么是反射:JAVA开发者使用反射大多是为了动态的操纵JAVA代码。能够分析类能力的程序为反射。
反射机制可以用来:
- 在程序运行中分析类的能力。(比如获取类的各项参数方法,根据类名动态创建实例对象等等)
- 在运行中查看对象。(比如查看对象域,当前运行对象的所属类,父类等)
- 可以编写操作通用的数组对象的代码。(使用反射和Array)
- 动态调用Method对象,类似于C++函数指针(确实很流弊)。
下面我们来看看反射机制的部分源码:
1.java.lang.Class
2.java.lang.reflect.Constructor
3.java.lang.reflect.Method
4.java.lang.reflect.Field
5.java.lang.reflect.Array
-----------------------------------------------------------------------------------------------------------------------------------------------------------
1.Class类
在程序运行期间,Java运行时系统始终为所有对象维护一个被称为运行时类型标识,这个信息跟踪这每个对象所属的类。虚拟机根据运行时类型信息
选择相应的方法执行。保存信息的类被称为
Class。
object.getClass():得到一个Classs类型的实例。
class.getName(): 得到含有包信息的类名如 "java.util.Date"
Class.forName("Class Name"): 根据类名得到Class类对象(这个会经常用到,动态加载类)
class.newInstance():创建一个类的实例或者对象(此接口只能用来创建无参数构造器的对象,接口很有用)
ps:创建带参数的构造器对象,可以使用class.getConstructor(...)获取带参数的构造器,然后constructor.newInstance(object,object...[])
2.异常捕获
java.lang.Throwable
反射机制的涉及操作基本编译器会强制程序员使用异常处理。
异常类型有两种:未检出异常和已检查异常。未检查异常出现运行此线程会终止,已检查
异常,编译器将会检查是否提供了处理器。 原则上,我们赢精心地编写代码来避免这些错误异常的发生,而不是将精力花费在写异常处理器上。
3.利用反射分析类的能力
反射机制最重要的内容——检查类的结构 java.lang.reflect提供了三个类Field、Method和Constructor分别用来描述类的域、方法、构造器。Modifier类返回
修饰符的信息。
具体如下:
java.lang.Class:
获取域:
Filed[] getdFileds():获取该类和超类中的公有域对象数组
Filed[] getDeclaredFileds() :获取本类声明的域对象数组
获取方法:
Method[] getMethods():获取该类和超类中的公有方法对象数组
Method[] getDeclareMethod() :获取本类声明的方法对象数组
获取构造器:
Constructor[] getConstructors() :
Constructor[] getDeclareConstructors():同上
其实,class类中还提供了获取特定域、方法和构造器的接口,有兴趣可以自己看源码。
java.lang.reflect.Field、Method、Constructor:
Class getDeclaringClass():返回对应的Class对象
Class[] getExceptionTypes():返回该方法描述的抛出的异常类型对象数组(Method、Constructor)
int getModifiers():返回修饰符,可以使用Modifier类的静态方法进行分析
String getName() :返回对应的名称字符串
Class[] getParameterTypes() :返回形参的参数类型
Class[] getReturnType() :返回方法的返回类型(Method)
java.lang.reflect.Modifier:
static String toString() :返回修饰符的字符串表示
static boolen isAbstruct()
static boolen isPublic() ...
4.在运行时使用反射分析对象
可以利用反射获取运行时对象的域值,具体操作如下:
People p= new People("Tom",19);
Class pc=p.getClass();
Filed f = pc.getDeclareField("name");
f.setAccessible(true);
Object name= f.get(p)
;//将对象传入
Ps:注意事项,反射机制的默认行为受限于java的访问控制,所以取域值只能遵循规则用get方法取,如果不加setAccessible会抛异常。
5.使用反射编写泛型数组代码
注意事项:Class.getComponentTpe()得到数组对象的数据类型,请参考java core
6.调用任意方法(类似C++函数指针)
在java的反射机制中,Method提供了接口,可以允许开发者调用任意方法。(建议能不用就不用,效率太低)
invoke的方法签名如下: Object invoke(Object obj,Object...args)
第一个参数为方法中的隐式参数(当前对象),其余的对象提供了显示参数,没有传null
实例代码:
People p= new People("Tom",19);
Class pc=p.getClass();
Method getNameMethod=p.getMethod("getName");
Method setNameMethod=p.getMethod("setName",java.lang.String.class);
Method.invoke(p,getNameMethod );//执行getName方法
Method.invoke(p,setNameMethod );//执行setName方法
ps:如果方法中没有隐式参数,p可以为null