java反射涉及到的内容有点多,但不难,主要是一些之前没见过的类型,本文先简单介绍一部分
在java.lang.reflect
包中定义了一些接口和类,简单记录下他们的作用
这些类都比较简单,对照API一看就懂,主要是平时用到的比较少,这里先简单说明下,不在此展开
类 | 说明 |
---|---|
AccessibleObject | Field、Method 和Constructor 对象的基类 |
Field | final类, 对应类或接口的单个字段 |
Method | final类, 对应类或接口的单独某个方法 |
Constructor<T> |
final类, 对应类的单个构造方法 |
Modifier | 对应类和成员访问修饰符, 如public,static,final,native,synchronized 等 |
Array | final类, 对应数组 |
Proxy | 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类 |
ReflectPermission | final类, 反射操作的Permission 类 |
另外反射机制还经常用到java.lang
中的类, 如Class
、Packate
还有各种原始类型等
这里先简单介绍下,后文还会详细说明这些接口
接口 | 说明 |
---|---|
AnnotatedElement | 被注解标注的元素都实现的接口 实现类有 AccessibleObject 及其子类,Class Package |
Member | 成员接口, 反映字段、方法、构造函数的信息 |
Type | 所有类型的父接口, 之后的文章会详细介绍 |
GenericDeclaration | 各种声明类型的父接口, 如Class,Constructor,Method |
TypeVariable<D extends GenericDeclaration> |
类型变量类型 |
ParameterizedType | 参数化类型, 如Collection<String> |
GenericArrayType | 数组类型, 它里面的元素为参数化类型或类型变量(上面那俩) |
WildcardType | 通配符类型, 如<?>, <? extends Number>, <? super Integer> |
InvocationHandler | 代理处理器接口 |
Object
, Class
和Type
的关系和区别所有的类都继承Object
是毫无疑问的, Class
也是类,也继承Object
Class
类特殊的地方是它在运行时用来描述类的各种元信息,对象是类的实例,而类在运行时的描述就是Class
Type
是个接口,用来表示某个对象是什么类型的,Class
类实现了好几个接口,其中一个就是Type
后面的文章内容更能体现出区别来
反射作用挺多, 比如反编译, 通过反射机制访问对象的属性、方法、构造方法等, 先简单给出一些示例
有如下三种方法:
Class.forName()
, 如:Class clazz = Class.forName("java.lang.String");
class
属性, 如:Class clazz = String.class;
getClass
方法, 如: Class clazz = user.getClass();
Class
实例的newInstance()
, 如:String str = (String)clazz.newInstance();
这些接口的关系可参考上面那幅图, 这里只详细说明AnnotatedElement、Member、InvocationHandler、GenericDeclaration
这几个接口
Type
接口及其字类在Type详解中详细说明
这个接口最简单, 实现了该接口的类都能添加注解, 其实现类有: AccessibleObject, Class, Constructor, Field, Method, Package
它有如下方法:
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
: 该类上是否存在annotationClass
这个注解Annotation[] getAnnotations()
: 获取这个元素上的所有注解(包括父类上被@Inherited
标记的注解)<A extends Annotation> A getAnnotation(Class<A> annotationClass)
: 获取这个元素上指定类型的注解, 没有返回nullAnnotation[] getDeclaredAnnotations()
: 获取直接标注在这个元素上的注解表示组成类的成员, 其实现类有: Constructor, Field, Method
它有如下方法:
boolean isSynthetic()
: 是否是复合类int getModifiers()
: 以数字形式返回修饰符String getName()
: 返回成员的简单名, 如: 属性名字, 方法名字(只有名字,不包括参数), 构造器名字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
}
}
代理处理器类的实例需要实现的接口, 只有一个方法:
Object invoke(Object proxy, Method method, Object[] args)
: 代理对象执行方法时真正调用的函数其中:
Object proxy
: 表示代理对象(比如通过Proxy.newProxyInstance()
得到的对象), 不是实现了该接口的代理处理器对象Method method
: 被代理对象的方法, 就是接口原来实现类里的方法, 代理对象执行的时候会调用被代理对象的方法(取决于代码怎么写)Object[] args
: 上面那个方法需要的参数通常代理处理器类的实例handler
会作为参数传到java代理类Proxy
的newProxyInstance
方法中来产生一个代理对象(与被代理对象实现了同一接口)
调用代理对象的方法时, 真正调用的就是上面的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方法
}
}
可以声明类型变量的实体的公共接口, 就是那些能够声明范型类型<T>
的地方, 注意是声明而不是使用.其实现类有: Class, Constructor, Method
它就一个方法:
TypeVariable<?>[] getTypeParameters()
: 按照声明顺序返回声明的类型变量对它可以这么理解:
在定义类或方法时, 我们一般可以声明范型, 如<T> T getData()
, 因此可以声明这些<T>、<F>
的实体, 都实现了该接口;
而那些声明出来的T、F
叫类型变量(TypeVariable
), 后面会说到.