1,什么是Java的反射?
经过对象所属类的Class对象,能够动态获取运行时对象的信息,或执行对象的方法。java
2,Class对象是什么?
每个类在JVM中都对应惟一一个java.lang.Class对象,能够经过newInstance()来调用无参构造建立一个实例对象。程序员
// 获取类加载器 ClassLoader getClassLoader() // 获取父类 Class<? super T> getSuperclass() // 获取继承父类时标明的泛型信息 Type getGenericSuperclass() // 获取该类实现的接口 Class<?>[] getInterfaces() // 获取实现父接口时标明的泛型信息 Type[] getGenericInterfaces() // 获取全部属性 Field[] getFields() // 获取当前类及全部继承的父类的public修饰的方法。仅包括public Method[]getMethods() // 获取当前类的全部方法,包括public/private/protected/default修饰的方法,不包括继承来的 Method[] getDeclaredMethods() // 获取全部构造方法 Constructor<?>[] getConstructors() // 获取具体名称的属性 Field getField(String name) // 获取具体的方法,仅包括public Method getMethod(String name, Class<?>... parameterTypes) // 获取具体的方法,包括public/private/protected/default修饰的方法,不包括继承来的 Method getDeclaredMethod(String name, Class<?>... parameterTypes) // 获取具体的构造方法 Constructor<T> getConstructor(Class<?>... parameterTypes) // 是否被指定注解修饰 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) // 获取全部类的注解 Annotation[] getAnnotations() // 获取指定的注解 <A extends Annotation> A getAnnotation(Class<A> annotationClass) // 获取指定的注解数组,包括继承父类的。JDK1.8支持,与@Repeatable()相关 <A extends Annotation> A getAnnotationsByType(Class<A> annotationClass) // 获取指定的注解数组,不包括继承父类的。JDK1.8支持,与@Repeatable()相关 <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass) // 获取修饰符 int getModifiers() // 获取全类名 String getName() // 获取简称 String getSimpleName() // 判断是不是接口 boolean isInterface() // 判断obj是不是该class的实例对象 boolean isInstance(Object obj)
3,如何获取Class对象?spring
4,Method对象是什么
Method对象表示Class中的方法信息。express
// 获取单独的方法名称 String getName() // 获取完整的方法信息(包括修饰符、返回值、路径、名称、参数、抛出值) String toGenericString() // 获取修饰符 int getModifiers() // 获取参数类型信息 Class<?>[] getParameterTypes() // 获取方法参数的泛型信息 Type[] getGenericParameterTypes() // 获取返回类型信息 Class<?> getReturnType() // 获取方法返回值的泛型信息 Type getGenericReturnType() // 获取异常信息 Class<?>[] getExceptionTypes() // 是否被指定注解修饰 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) // 获取方法注解 Annotation[] getAnnotations() // 获取指定的注解 <T extends Annotation> T getAnnotation(Class<T> annotationClass) // 获取方法参数的全部注解 Annotation[][] getParameterAnnotations() // 获取指定的注解数组,包括继承父类的。JDK1.8支持,与@Repeatable()相关 <T extends Annotation> T[] getAnnotationsByType(Class<A> annotationClass) // 获取指定的注解数组,不包括继承父类的。JDK1.8支持,与@Repeatable()相关 <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<A> annotationClass) // 是不是桥接方法。JDK 1.5 引入泛型后,为了使Java的泛型方法生成的字节码和 1.5 版本前的字节码相兼容,由编译器自动生成的方法 boolean isBridge() // 是不是默认方法。JDK1.8开始接口容许有默认方法 boolean isDefault() // 是不是可变参方法。JDK1.5开始支持方法入参能够是可变参 boolean isVarArgs() // 是不是合成方法。JDK1.5开始支持枚举类,这种类型不是程序员写的,是编译器生成的。涉及枚举类的地方会由编译器生成一些该类型方法 boolean isSynthetic() // 反射执行obj对象的该方法,参数为args Object invoke(Object obj, Object... args)
5,Field对象是什么?
Field对象表示Class中的属性信息。数组
// 获取属性名 String getName() // 获取修饰符 int getModifiers() // 是不是枚举类型 boolean isEnumConstant() // 是不是合成类型 boolean isSynthetic() // 获取属性类型 Class<?>getType() // 获取属性的泛型信息 Type getGenericType() // 获取obj对象的当前属性值 Object get(Object obj) // 将obj对象的当前属性设置为value void set(Object obj, Object value) // 是否被指定注解修饰 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) // 获取属性的全部注解 Annotation[] getAnnotations() // 获取属性上的指定类型的注解 <T extends Annotation> T getAnnotation(Class<T> annotationClass) // 获取指定的注解数组,包括继承父类的。JDK1.8支持,与@Repeatable()相关 <T extends Annotation> T[] getAnnotationsByType(Class<A> annotationClass) // 获取指定的注解数组,不包括继承父类的。JDK1.8支持,与@Repeatable()相关 <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<A> annotationClass)
6,其余好比Package对象,Constructor对象,URL对象,在反射中的使用频率小,这里就不研究了。.net
注意:code
因为编译会进行泛型擦除致使编译后的字节码是没有泛型信息的,因此运行期没法经过反射获得泛型信息。对象
访问private的方法和变量须要设置method.setAccessible(true)或field.setAccessible(true)。blog
invoke()执行方法时方法的参数类型及顺序要正确。继承
如何经过桥接方法获取对应的实际方法呢?能够查看spring中org.springframework.core.BridgeMethodResolver
类的源码。其实是经过判断方法名、参数的个数以及泛型类型参数来获取的。
反射get和set的3种方式:
java.beans.PropertyDescriptor
private Object getValueByReflect(Object obj, String expression) throws NoSuchFieldException, SecurityException, IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class<? extends Object> clazz = obj.getClass(); Field field = clazz.getDeclaredField(expression); PropertyDescriptor pd=new PropertyDescriptor(field.getName(),clazz); Method method = pd.getReadMethod(); return method.invoke(obj); }
参考资料: