反射

前言

反射技术是非常关键的一项技术,在动态代理、spring IOC容器、AOP中广泛应用。某些场景下,在类编译时并不知道类的确切类型,只有在运行时才可确定其类型。

反射简介及使用

反射指运行时获取类的相关信息,包括类的字段、方法构造器等信息。有了这些信息我们可以做很多事情,例如类实例对象的创建;方法名称、参数的获取;字段名称获取等。反射在运行时获取这些信息,需要在运行时打开和检查Class文件。

类信息获取

获取类信息有四种方法:类对象、Class的forName()方法、类实例对象的getClass()方法、类加载器的loadClass()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 根据类对象获取类信息
public Object getObjectByClass(Class<?> targetClass) throws Exception {
Class<?> cls = targetClass;
Object obj = cls.newInstance();
return obj;
}
// 根据类全限定名称获取类
public Object getObjectByClassName(String className) throws Exception{
Class<?> cls = Class.forName(className);
Object obj = cls.newInstance();
return obj;
}
// 根据类实例对象获取类
public Object getObjectByInstance(Object instance) throws Exception {
Class<?> cls = instance.getClass();
Object obj = cls.newInstance();
return obj;
}
// 根据类的全限定名称加载类
public Object getObjectByClassLoader(String className) throws Exception {
Class<?> cls = this.getClass().getClassLoader().loadClass(className);
Object obj = cls.newInstance();
return obj;
}

字段获取

可以通过实例对象获取字段信息(字段名称、类型、值),并且可以对字段进行复制等操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public Object getFieldByName(Object instance, String fieldName, Object value) throws Exception {
Class<?> cls = instance.getClass();
// 根据字段名称获取字段
Field field = cls.getField(fieldName);
// 输出字段名称
System.out.println(field.getName());
// 输出instant实例对象中该字段的值
System.out.println(field.get(instance));
// 获取字段的类型
Class<?> fieldClass = field.getDeclaringClass();
System.out.println(fieldClass.getName());
// 对字段赋值
field.setAccessible(true);
field.set(instance, value);
return field;
}

方法信息获取

通过类信息可获取方法的名称、方法参数、返回值类型等信息,还可通过invoke()方法执行实例对象的某个方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public Object[] getMethodByName(Object instance, Object[] params) throws Exception {
Class<?> cls = instance.getClass();
Method[] methods = cls.getMethods();
for (Method method : methods) {
// 获取方法名称
System.out.println(method.getName());
// 获取方法参数
Object[] ps = method.getParameters();
for(Object p : ps){
System.out.println(p.toString());
}
// 获取方法返回值的类型
AnnotatedType annotatedType = method.getAnnotatedReturnType();
System.out.println(annotatedType.getType().getTypeName());
// 执行方法调用
method.setAccessible(true);
method.invoke(instance, params);
}
return methods;
}

构造方法获取

根据构造函数的入参类型,可以获取类的构造函数。默认构造函数的入参为null,并可通过构造函数创建对象。getDeclaredConstructor(null)或者getConstructor(null)均可获取默认构造。

1
2
3
4
5
6
public Object getConstructor(Object instance) throws Exception{
Class<?> cls = instance.getClass();
Constructor constructor = cls.getDeclaredConstructor(null);
Object object = constructor.newInstance();
return object
}