我所理解的JDK反射

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

  1. Class.forName("com.test.A");
  2. a.getClass();
  3. com.test.A.class;
    区别详见类加载机制

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

  1. 因为编译会进行泛型擦除致使编译后的字节码是没有泛型信息的,因此运行期没法经过反射获得泛型信息。对象

  2. 访问private的方法和变量须要设置method.setAccessible(true)或field.setAccessible(true)。blog

  3. invoke()执行方法时方法的参数类型及顺序要正确。继承

  4. 如何经过桥接方法获取对应的实际方法呢?能够查看spring中org.springframework.core.BridgeMethodResolver类的源码。其实是经过判断方法名、参数的个数以及泛型类型参数来获取的。

反射get和set的3种方式

  1. 手动拼get和set的方法名,而后调用getMethod(name)再调用invoke()来执行
  2. 获取属性field,再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);
}

参考资料:

  1. 以上内容为笔者平常琐屑积累,已无从考究引用。若是有,请站内信提示。
相关文章
相关标签/搜索