提到java语言的高级特性,反射绝对是Top1级别的,在大量开源框架中的应用范例比比皆是,那么需要了解清楚反射到底是什么?为什么要使用反射?如何使用反射?(what,why,how)
什么是反射?
正常场景下,java从源码到运行有3个阶段:
source class runtime
反射提供的是runtime阶段获取类的class实例、方法、属性、注解,并且能够调用类的方法的途径,这种动态获取类信息和调用类方法的机制被称之为反射
为什么要使用反射?
正常的实例化一个对象
ClassA objA = new ClassA();
objA.sayHello();
通过反射去实例化一个对象
Class objA = ClassA.class;
Method method = objA.getMethod("sayHello");
method.invoke(objA.newInstance());
在source阶段实际上二者并无任何区别,反射也没有体现出任何的优势,那么任何一个java开发人员必然会问为什么要使用反射?
反射的重点在于runtime阶段的获取类信息和调用类方法,那么当你的编码过程中中有“部分信息是source阶段不清晰,需要在runtime阶段动态临时加载”这种场景,反射就可以派上用场了
我们考虑几个编码场景:
1、编码阶段不知道需要实例化的类名是哪个,需要在runtime从配置文件中加载:
Class clazz = class.forName("xxx.xxx.xxx")
clazz.newInstance();
2、在runtime阶段,需要临时访问类的某个私有属性
ClassA objA = new ClassA();
Field xxx = objA.getClass().getDeclaredField("xxx")
xxx.setAccessible(true);
所以,反射的优点在于“有些编码需求在source阶段无法实现,只能在runtime阶段通过反射实现”,而非“source阶段正常编码方式能解决的,反射的方式能解决的更好”,所以比较反射和正常编码方式的优劣是没有意义的,反射解决的是正常编码无法解决的编码场景,如果正常编码方式可以解决的,强行使用反射反而是毫无意义的,编码不是为了show技巧。
反射应用范例代码
实现对类或者对象的构造器、方法、属性、注解的获取和操作,具体作用见代码中的注释描述
public class ReflectionHelper {
/**
* Reflection Test Code
*
* @param args
*/
public static void main(String[] args) {
SSHClient sshClient = new SSHClient();
// 获取class名称
System.out.println("01-----获取class名称-----");
System.out.println(sshClient.getClass().getName());
System.out.println(sshClient.getClass().getSimpleName());
System.out.println(sshClient.getClass().getTypeName());
Class> clazz1 = null;
Class> clazz2 = null;
Class> clazz3 = null;
// 获取对象或者类的Class实例
try {
clazz1 = Class.forName(sshClient.getClass().getName());
clazz2 = sshClient.getClass();
clazz3 = ReflectionUtils.class;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
// 获取类的构造函数,用构造函数实例一个对象
for (Constructor> clazz1Cstor : clazz1.getConstructors()) {
System.out.println(clazz1Cstor.getName());
try {
SSHClient client1 = (SSHClient) clazz1.newInstance();
SSHClient client2 = (SSHClient) clazz1Cstor.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
// 获取类定义的方法、属性
System.out.println("02-----获取类定义的方法、属性-----");
try {
SSHClient client = (SSHClient) clazz1.newInstance();
Method setHostMethod = clazz1.getDeclaredMethod("setHost", String.class);
setHostMethod.invoke(client, "111");
Field field = client.getClass().getDeclaredField("host");
field.setAccessible(true);
System.out.println(field.get(client));
field.set(client,"a new host");
System.out.println(field.get(client));
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
// 获取类的注解
System.out.println("03-----获取类使用的注解-----");
for (Annotation annotation : clazz1.getAnnotations()) {
System.out.println(annotation.getClass().getName());
System.out.println(annotation.toString());
System.out.println(annotation.annotationType());
}
}
}
运行结果: