1.1 首先了解些反射基本知识
指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法。这种动态获取信息,以及动态调用对象方法的功能叫java语言的反射机制。
反射的关键类就是Class类,我们一般有三种获取Class的方式:
第一种: 通过加载包路径获取class
Class c =Class.forName("com.xxxx.xxxx")
第二种: 直接通过类.class
Class c = Person.class;
第三种: 通过类实例对象获取
Person p = new Person();
Class c = p.getClass();
好了,我们拿到Class 干什么呢?Class 类里到底包含了什么?这就涉及到反射的作用了,反射有什么用呢,我们可以从网上了解到很多。举个例子,我们想通过注解获取对应的方法或者参数,这时候就可以用到反射,反射可以减少我们的代码,可以让不可能变成可能。spring源码里就是用了很多反射机制。当然我也不打算去研究反射原理,就像记录下各种用法。
我们首先看下Class到底是个什么东西,看源码吧,太多了我就不粘了,粘两个方法以示尊敬。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
public T newInstance()
throws InstantiationException, IllegalAccessException
{
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
}
// NOTE: the following code may not be strictly correct under
// the current Java memory model.
// Constructor lookup
if (cachedConstructor == null) {
if (this == Class.class) {
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
c.setAccessible(true);
return null;
}
});
cachedConstructor = c;
} catch (NoSuchMethodException e) {
throw (InstantiationException)
new InstantiationException(getName()).initCause(e);
}
}
Constructor<T> tmpConstructor = cachedConstructor;
// Security check (same as in java.lang.reflect.Constructor)
int modifiers = tmpConstructor.getModifiers();
if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
if (newInstanceCallerCache != caller) {
Reflection.ensureMemberAccess(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
// Run constructor
try {
return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
Unsafe.getUnsafe().throwException(e.getTargetException());
// Not reached
return null;
}
}
//省略class源码...........
}
1.2 反射常用的一些方法
public class Person {
private String name;
private Integer age;
private Person(){
}
public Person(String name,Integer age){
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
@Target({ElementType.METHOD,ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Mapping {
String value() default "";
}
1.2.1 获取类的构造函数
Class<Person> clazz = Person.class;
//获取所有的构造方法
for (Constructor<?> declaredConstructor : clazz.getDeclaredConstructors()) {
logger.debug("构造方法:{}", declaredConstructor.toString());
//也可以获取参数类型
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
//获取构造方法上注解信息Mapping为注解类
Mapping annotation = declaredConstructor.getAnnotation(Mapping.class);
logger.debug("注解信息:{}", annotation.value());
}
//调用构造方法
Class<?>[] param = {String.class,Integer.class};
Constructor<Person> declaredConstructor = clazz.getDeclaredConstructor(param);
//访问私有构造方法
declaredConstructor.setAccessible(true);
Person zhangsan = declaredConstructor.newInstance("zhangsan", 1);
logger.debug("name:{},age:{}",zhangsan.getName(),zhangsan.getAge());
1.2.2 获取类的方法
获取类的方法和获取构造函数基本一致,获取注解也是通过getAnnotation().
//获取类的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
logger.debug("所有方法:{}", declaredMethod.toString());
}
//调用方法
Person person = new Person("lisi",10);
Class<?>[] paramT = {String.class};
Method method = clazz.getDeclaredMethod("setName", paramT);
//调用私有方法
method.setAccessible(true);
method.invoke(person,"zhangsan");
logger.debug("person name is {}",person.getName());
1.2.2 获取类的属性
//获取类的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
logger.debug("所有属性:{}", declaredField.toString());
}
//修改属性值
Field field = clazz.getDeclaredField("age");
field.setAccessible(true);
field.set(person,20);
logger.debug("person age is {}",person.getAge());
1.2.2 获取类、方法、属性、参数上的Annotation注解值
这个其实很简单。如果想获取方法上的注解,就现获取方法Method,然后通过method.getgetAnnotation(),直接看代码:
//获取类上的
clazz.getAnnotation(Mapping.class);
//获取方法上的
Method method = clazz.getDeclaredMethod("setName", paramT);
Method.getAnnotation(Mapping.class)
//获取属性上的
Field field = clazz.getDeclaredField("age");
field.getAnnotation(Mapping.class);
//获取参数上的
for (Parameter parameter : method.getParameters()) {
Mapping annotation = parameter.getAnnotation(Mapping.class);
}
到此,还有很多没有方法没有涉及其中,有空还是可以多多研究研究。