Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。
Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。
这种“看透”class的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。
Class类:代表一个类,位于java.lang包下。
Field类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor类:代表类的构造方法。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法。
获取类的Class对象:
要想使用反射,首先需要获得待操作的类所对应的Class对象。
Java中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class对象。
这个Class对象是由JVM生成的,通过它能够获悉整个类的结构。
常用的获取Class对象的3种方式:
1).使用Class类的静态方法。例如: Class.forName("java.lang.String");
2).使用类的.class语法。如: String.class;
3).使用对象的getClass()方法。如:String str = "aa"; Class<?> classType1 = str.getClass();
获取类的Fields
可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。JAVA 的Class<T>类提供了几个方法获取类的属性。
public FieldgetField(String name) | 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段 |
public Field[] getFields() | 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段 |
public FieldgetDeclaredField(Stringname) | 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段 |
public Field[] getDeclaredFields() | 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段 |
运行结果:public static void main(String[] args) throws ClassNotFoundException {
// TODO Auto-generated method stub
Class<?> pc3 = Class.forName("reflect.Person");
Field[] fields=pc3.getFields();
for (Field f : fields)
{
System.out.println("field:"+f);
}
Field[] fields2= pc3.getDeclaredFields();
for (Field f : fields2)
{
System.out.println("d field:"+f);
}
}field:public java.lang.String reflect.Person.name d field:private java.lang.String reflect.Person.password d field:public java.lang.String reflect.Person.name
可见getFields和getDeclaredFields区别:getFields返回的是申明为public的属性,包括父类中定义,
getDeclaredFields返回的是指定类定义的所有定义的属性,不包括父类的。
获取类的Method
通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法
Class<T>类提供了几个方法获取类的方法。
public MethodgetMethod(String name,Class<?>... parameterTypes) | 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法 |
public Method[] getMethods() | 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法 |
public MethodgetDeclaredMethod(Stringname,Class<?>... parameterTypes) |
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法 |
public Method[] getDeclaredMethods() | 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法 |
获取类的Constructor
通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例
Class<T>类提供了几个方法获取类的构造器。
public Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法 |
public Constructor<?>[] getConstructors() | 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法 |
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) |
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法 |
public Constructor<?>[] getDeclaredConstructors() |
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。它们是公共、保护、默认(包)访问和私有构造方法 |
输出:Constructor<?>[] cons=pc3.getConstructors();
for (int i = 0; i < cons.length; i++) {
System.out.println("cons: "+cons[i]);
}
通过反射获取类的Field对象,调用Field方法设置或获取值
每次NativeMethodAccessorImpl.invoke()方法被调用时,都会增加一个调用次数计数器,看超过阈值没有;一旦超过,则调用MethodAccessorGenerator.generateMethod()来生成Java版的MethodAccessor的实现类,并且改变DelegatingMethodAccessorImpl所引用的MethodAccessor为Java版。后续经由DelegatingMethodAccessorImpl.invoke()调用到的就是Java版的实现了。注意到关键的invoke0()方法是个native方法。它在HotSpot VM里是由JVM_InvokeMethod()函数所支持的,扯个额外话:想想大多数java有关的东西,如果你愿意去看源码分析的话,总会找到jvm这层,当然还有大神继续研究Hotspot的里面的C源码,我觉得主要知识点到这一层就算是比较深入了 。
再看DelegatingMethodAccessorImpl:
这是一个间接层,方便在native与Java版的MethodAccessor之间实现切换。
native结束,再看java版本:MethodAccessorGenerator。它的基本工作就是在内存里生成新的专用Java类,并将其加载。
private static synchronized String generateName(boolean isConstructor,
boolean forSerialization)
{
if (isConstructor) {
if (forSerialization) {
int num = ++serializationConstructorSymnum;
return "sun/reflect/GeneratedSerializationConstructorAccessor" + num;
} else {
int num = ++constructorSymnum;
return "sun/reflect/GeneratedConstructorAccessor" + num;
}
} else {
int num = ++methodSymnum;
return "sun/reflect/GeneratedMethodAccessor" + num;
}
}
上面贴出来的方法就是产生名字的。至于大神RednaxelaFX贴出来解释GeneratedMethodAccessor1 这段看不懂。如有大神理解,还请多多留言指正。http://rednaxelafx.iteye.com/blog/548536