一、反射的概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象(Class对象)。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。
二、解刨Class对象
反射就是把java类中的各种成分映射成一个个的Java对象。例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。其实,一个类中这些成员方法、构造方法、在加入类中都有一个类来描述,Constructor(构造方法类)、Method(方法类)、Filed(属性类)、Annotation(注解类)。注意,通过Class对象,可以获得类的成员变量、方法、构造方法、包等等信息。
1、Class对象
类是程序的一部分,每个类都有一个Class对象。当创建一个新类时,就会产生一个Class对象,被保存在一个同名的.class文件中。枚举是一种类,注释是一种接口。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。
1.1、获取构造方法信息
不包含父类的。
getConstructor(Class<?>... parameterTypes) 获取当前类某个的”公有的”构造方法 | |
Constructor<?>[] | getConstructors() 获取当前类所有”公有的”构造方法 |
getDeclaredConstructor(Class<?>... parameterTypes) 获取当前类”某个构造方法”(私有、受保护、默认、公有) | |
Constructor<?>[] | getDeclaredConstructors() 获取当前类所有的构造方法(私有、受保护、默认、公有) |
1.2、获取属性信息
getField和getFields可以获取当前类和父类的;
getDeclaredField和getDeclaredFields获取当前类的;
一般使用getDeclaredFields方法。
Field[] | getFields() 获取当前类和父类所有的”公有字段” |
getDeclaredField(String name) 获取当前类某个字段(私有、受保护、默认、公有) | |
Field[] | getDeclaredFields() 获取当前类所有字段(私有、受保护、默认、公有) |
1.3、获取方法信息
getMethod和getMethods可以获取当前类和父类的;
getDeclaredMethod和getDeclaredMethods获取当前类的;
getMethod(String name, Class<?>... parameterTypes) 获取当前类和父类某个的”公有的”方法 | |
Method[] | getMethods()获取当前类和父类所有”公有的”方法 |
getDeclaredMethod(String name, Class<?>... parameterTypes)获取当前类”某个方法”(私有、受保护、默认、公有) | |
Method[] | getDeclaredMethods()获取当前类所有的方法(私有、受保护、默认、公有) |
1.4、获取注解信息
getAnnotations() 返回此类上存在的及可继承的所有注解对象。 | |
getDeclaredAnnotations()返回直接存在此类的所有注解对象。 | |
<A extends Annotation> | getAnnotation(Class<A> annotationClass)类上若存在指定的注解对象类型,则返回注解对象,否则返回NULL |
一般是使用自定义注解,然后通过Class对象的getDeclaredFields() 获取当前类所有字段(私有、受保护、默认、公有),然后循环遍历,获取字段上的注解,再进行操作。
1.5、其它常用方法
ClassLoader | getClassLoader() 返回该类的类加载器。 |
T | cast(Object obj) 将一个对象强制转换成此 Class 对象所表示的类或接口。 |
static Class<?> | forName(String className) 返回与带有给定字符串名的类或接口相关联的 Class 对象。 |
String | getName() 返回此 Class 对象所表示的实体名称,类全路径。 |
InputStream | getResourceAsStream(String name) 查找具有给定名称的资源。 |
String | getSimpleName() 返回源代码中给出的底层类的简称(Class类名称)。 |
boolean | isAssignableFrom(Class<?> cls) 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。 |
newInstance()创建此 Class 对象所表示的类的一个新实例。 |
2、Constructor(构造方法类)
newInstance(Object... initargs) 使用该构造方法创建对象实例,initargs为构造方法参数。 |
从类 java.lang.reflect.AccessibleObject 继承的方法setAccessible(boolean flag),为true暴力访问(忽略掉访问修饰符)。
3、Method(方法类)
Object | invoke(Object obj, Object... args)调用obj对象的该方法,args为方法参数 。 |
从类 java.lang.reflect.AccessibleObject 继承的方法setAccessible(boolean flag),为true暴力访问(忽略掉访问修饰符)。
4、Filed(属性类)
| getAnnotation(Class<T> annotationClass) 如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。 |
getDeclaredAnnotations() 返回直接存在于此元素上的所有注释。 | |
Class<?> | getType()返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。 |
getName() 返回此 Field 对象表示的字段的名称。 | |
void | set(Object obj, Object value) 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 |
从类 java.lang.reflect.AccessibleObject 继承的方法setAccessible(boolean flag),为true暴力访问(忽略掉访问修饰符)。
5、Annotation(注解类)
getValue() 返回属性值,可能为 null。 |
三、总结
在日常开发中,通常将自定义注解与反射结合使用。例如,在某个字段上使用自定义注解,通过getDeclaredFields 获取所有字段,通过getAnnotation(Class<T> annotationClass) 判断字段上是否有自定义注解,若是有,则进一步处理。