java中的反射

java反射涉及到的内容有点多,但不难,主要是一些之前没见过的类型,本文先简单介绍一部分



反射相关的类和接口简介

java.lang.reflect包中定义了一些接口和类,简单记录下他们的作用

相关类说明

这些类都比较简单,对照API一看就懂,主要是平时用到的比较少,这里先简单说明下,不在此展开

说明
AccessibleObject Field、MethodConstructor对象的基类
Field final类, 对应类或接口的单个字段
Method final类, 对应类或接口的单独某个方法
Constructor<T> final类, 对应类的单个构造方法
Modifier 对应类和成员访问修饰符, 如public,static,final,native,synchronized
Array final类, 对应数组
Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类
ReflectPermission final类, 反射操作的Permission

另外反射机制还经常用到java.lang中的类, 如ClassPackate还有各种原始类型等

相关接口继承关系图

反射相关接口继承关系图

相关接口说明

这里先简单介绍下,后文还会详细说明这些接口

接口 说明
AnnotatedElement 被注解标注的元素都实现的接口
实现类有AccessibleObject及其子类,ClassPackage
Member 成员接口, 反映字段、方法、构造函数的信息
Type 所有类型的父接口, 之后的文章会详细介绍
GenericDeclaration 各种声明类型的父接口, 如Class,Constructor,Method
TypeVariable<D extends GenericDeclaration> 类型变量类型
ParameterizedType 参数化类型, 如Collection<String>
GenericArrayType 数组类型, 它里面的元素为参数化类型或类型变量(上面那俩)
WildcardType 通配符类型, 如<?>, <? extends Number>, <? super Integer>
InvocationHandler 代理处理器接口

Object, ClassType的关系和区别

所有的类都继承Object是毫无疑问的, Class也是类,也继承Object
Class类特殊的地方是它在运行时用来描述类的各种元信息,对象是类的实例,而类在运行时的描述就是Class
Type是个接口,用来表示某个对象是什么类型的,Class类实现了好几个接口,其中一个就是Type
后面的文章内容更能体现出区别来


反射的具体功能

反射作用挺多, 比如反编译, 通过反射机制访问对象的属性、方法、构造方法等, 先简单给出一些示例

获取类

有如下三种方法:

  1. 通过Class.forName(), 如:Class clazz = Class.forName("java.lang.String");
  2. 通过类的class属性, 如:Class clazz = String.class;
  3. 通过实例对象的getClass方法, 如: Class clazz = user.getClass();

获取对象实例

  1. 通过Class实例的newInstance(), 如:String str = (String)clazz.newInstance();

反射相关接口的详细说明

这些接口的关系可参考上面那幅图, 这里只详细说明AnnotatedElement、Member、InvocationHandler、GenericDeclaration这几个接口
Type接口及其字类在Type详解中详细说明

AnnotatedElement

这个接口最简单, 实现了该接口的类都能添加注解, 其实现类有: AccessibleObject, Class, Constructor, Field, Method, Package
它有如下方法:

  1. boolean isAnnotationPresent(Class<? extends Annotation> annotationClass): 该类上是否存在annotationClass这个注解
  2. Annotation[] getAnnotations(): 获取这个元素上的所有注解(包括父类上被@Inherited标记的注解)
  3. <A extends Annotation> A getAnnotation(Class<A> annotationClass): 获取这个元素上指定类型的注解, 没有返回null
  4. Annotation[] getDeclaredAnnotations(): 获取直接标注在这个元素上的注解

Member

表示组成类的成员, 其实现类有: Constructor, Field, Method 它有如下方法:

  1. boolean isSynthetic(): 是否是复合类
  2. int getModifiers(): 以数字形式返回修饰符
  3. String getName(): 返回成员的简单名, 如: 属性名字, 方法名字(只有名字,不包括参数), 构造器名字
  4. Class<?> getDeclaringClass(): 返回声明该成员的声明类
// getName方法的测试
package com.test;
public class TestMember {
    private String name;              // 属性名为: name
    public void hello(String name) {} // 方法名(不包括参数)为: hello
    public TestMember(String name) {} // 构造器名为: com.test.TestMember
    public static void main(String[] args) throws Exception {
        System.out.println(TestMember.class.getDeclaredField("name").getName());                    // name
        System.out.println(TestMember.class.getDeclaredMethod("hello", String.class).getName());    // hello
        System.out.println(TestMember.class.getDeclaredConstructor(String.class).getName());        //com.test.TestMember
        System.out.println(TestMember.class.getDeclaredField("name").getDeclaringClass().getName());//com.test.TestMember
    }
}

InvocationHandler

代理处理器类的实例需要实现的接口, 只有一个方法:

  1. Object invoke(Object proxy, Method method, Object[] args): 代理对象执行方法时真正调用的函数

其中:

  • Object proxy: 表示代理对象(比如通过Proxy.newProxyInstance()得到的对象), 不是实现了该接口的代理处理器对象
  • Method method: 被代理对象的方法, 就是接口原来实现类里的方法, 代理对象执行的时候会调用被代理对象的方法(取决于代码怎么写)
  • Object[] args: 上面那个方法需要的参数

通常代理处理器类的实例handler会作为参数传到java代理类ProxynewProxyInstance方法中来产生一个代理对象(与被代理对象实现了同一接口)
调用代理对象的方法时, 真正调用的就是上面的invoke函数.
还是来个例子吧(HelloImpl实现了Hello接口, 并实现了sayHello()方法)

// 代理处理器类
public class AOPHandler implements InvocationHandler {
    private Object target;  // 这个用来表示被代理的对象
    public AOPHandler(Object target) {
        this.target = target;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("proxy:" + proxy.getClass().getName());   // proxy:com.sun.proxy.$Proxy0
        System.out.println("method:" + method.getClass().getName()); // proxy:java.lang.reflect.Method
        return method.invoke(target, args);  // 调用被代理对象的的方法, 即 target 的 method
    }
}
// 测试类
public class ProxyTest {
    public static void main(String[] args) throws Exception {
        Object obj = Class.forName("com.test.HelloImpl").newInstance();
        InvocationHandler handler = new AOPHandler(obj);  // 创建代理处理器对象的时候把被代理的对象传进去
        // 这里生成代理类对象, 参数依次为: 被代理对象的ClassLoader, 被代理对象实现的所有接口, 代理处理器
        Hello proxy = (Hello) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
        proxy.sayHello();  // 这就调用了那个invoke方法
    }
}

GenericDeclaration

可以声明类型变量的实体的公共接口, 就是那些能够声明范型类型<T>的地方, 注意是声明而不是使用.其实现类有: Class, Constructor, Method
它就一个方法:

  1. TypeVariable<?>[] getTypeParameters(): 按照声明顺序返回声明的类型变量

对它可以这么理解:
在定义类或方法时, 我们一般可以声明范型, 如<T> T getData(), 因此可以声明这些<T>、<F>的实体, 都实现了该接口;
而那些声明出来的T、F叫类型变量(TypeVariable), 后面会说到.