反射机制
反射是Java语言的一个特性,是Java被视为动态语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括modifiers(如public,static等)、superclass(如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。Java可以加载一个运行时才得知名称的class,获得其完整结构。
A Simple Example
1 | import java.lang.reflect.*; |
输出结果
1 | $ java DumpMethods java.util.Stack |
列出了java.util.Stack类的所有方法名和签名。
这个程序用class.forName加载特定的类,然后调用getDeclaredMethods取出类中定义的方法列表。java.lang.reflect.Method是一个代表类方法的类。
JDK中提供的Reflection API
Interfaces
AnnotatedElement
GenericArrayType
GenericDeclaration
InvocationHandler
Member
ParameterizedType
Type
TypeVariable
WildcardType
Classes
AccessibleObject
Array
Constructor
Field
Method
Modifier
Proxy
ReflectPermission
Exceptions
InvocationTargetException
MalformedParameterizedTypeException
UndeclaredThrowableException
Errors
GenericSignatureFormatError
Java反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任一个对象的方法
- 在运行时创建新类对象
在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。
用于测试的类:
1 | class Type { |
1.获取类的Class对象
Class类的实例表示正在运行的Java应用程序中的类和接口。
- 调用getClass
1
2
3Boolean var1 = new Boolean("true");
Class classType1 = var1.getClass();
System.out.println(classType1); - 运用.class语法
1
2Class classType2 = Boolean.class;
System.out.println(ClassType2) - 运用static method Class.forName()
1
2Class classType3 = Class.forName("java.lang.Boolean");
System.out.println(classType3); - 运用primitive wrapper classes的TYPE语法(这里返回的是原生类型,和Boolean.class返回的不同)
1
2Class classType4 = Boolean.TYPE;
System.out.println(classType4);
2.获取类的Fields
可以通过反射机制得到某个类的某个属性,然后改变对应于这个类的某个实例的该属性值。Java的Class类提供了几个方法获取类的属性。
public Field getField(String name)
返回一个Field对象,它反映此Class对象所表示的类或接口的指定public成员字段。public Field[] getFields()
返回Field对象的数组,这些对象反映此Class对象所表示的类或接口的所有可访问public字段。public Field getDeclaredField(String name)
返回一个Field对象,它反映此Class对象所表示的类或接口的指定已声明字段。public Field[] getDeclaredFields()
返回Field对象的数组,这些对象反映出此Class对象所表示的类或接口声明的所有字段。
1 | Class classType = ExtendType.class; |
可见getFields和getDeclaredFields区别:
getFields返回的是声明为public的属性,包括父类中定义,
getDeclaredFields返回的是指定类定义的所有定义的属性,不包括父类的。
3.获取类的Method
通过反射机制得到某个类的某个方法,然后调用对应于这个类的某个实例的该方法。Class类提供了几个获取类方法的方法。
public Method getMethod(String name, Class<?>... parameterTypes)
返回一个Method对象,它反映此Class对象所表示的类或接口的指定public成员方法。public Method[] getMethods()
返回Method对象的数组,这些对象反映此Class对象所表示的类或接口的public成员方法,包括继承的方法。public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个Method对象,该对象反映此Class对象所表示的类或接口的指定已声明方法。public Method[] getDeclaredMethods()
返回Method对象的数组,这些对象反映此Class对象表示的类或接口声明的所有方法,但不包括继承的方法。
1 | Class classType = ExtendType.class; |
4.获取类的Constructor
通过反射机制得到某个类的构造器,然后调用该构造器创建该类的一个实例,Class类提供了几个方法获取类的构造器。
public Constructor<T> getConstructor(Class<?>... parameterType)
返回一个Constructor对象,它反映此Class对象所表示的类的指定public构造方法。public Constructor<?>[] getConstructors()
返回Constructor对象的数组,这些对象反映此Class对象所表示的类的所有public构造方法。public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一个Constructor对象,它反映此Class对象所表示的类或接口的指定构造方法。public Constructor<?>[] getDeclaredConstructors()
返回Constructor对象的数组,这些对象反映此Class对象表示的类声明的所有构造方法。
1 | Constructor[] constructors = classType.getConstructors(); |
5.新建类的实例
通过反射机制创建新类的实例,有几种方法可以创建。
- 调用无自变量ctor
(1)调用类的Class对象的newInstance方法,该方法会调用对象的默认构造函数,如果没有默认构造函数,会调用失败。
1 | Class classType = ExtendType.class; |
(2)调用默认Constructor对象的newInstance方法
1 | Class classType = ExtendType.class; |
- 调用带参数ctor
(3)调用带参数Constructor对象的newInstance方法
1 | Class classType = ExtendType.class; |
6.调用类的函数
通过反射获取类Method对象,调用其Invoke方法调用此函数。
1 | Class classType = ExtendType.class; |
7.设置/获取类的属性值
通过反射获取类的Field对象,调用Field方法设置或获取值。
1 | Class classType = ExtendType.class; |