1. 反射是什么?
反射是一种机制,是一种能力,是指JVM在运行过程中,对于任意一个类,都可以知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意方法和属性。
2. 反射的原理?如果你对 JVM 的类加载机制有所了解(这里不了解也没关系),就会知道,类在编译的时候,会生成一个 .class 文件,当类被使用的时候,这个 class 文件就会被读取并被载入到虚拟机中,生成对应类型的 Class 对象,这个被创建出的 Class 对象中就包含了我们原本的类中一切信息,通过这个对象,我们就可以去获取这个类的属性和方法,并且把这些属性和方法转换成一个对象,从而达到改变/执行的目的。
3. 反射的使用?使用反射的第一步,是获取一个 Class 对象,我们可以通过以下几种方式去获取一个 Class 对象
获取 Class 对象 // 1. 根据类的全限定名 Class str1 = Class.forName("java.lang.String"); // 2. .class获取 Class str2 = String.class; // 3. 继承自 Object 类的 getClass 方法 String s = new String(); Class str3 = s.getClass();拿到了 Class 对象,下面我就可以对这个 Class 对象进行进一步的剖析,获取它的构造方法,字段和一般方法
获取Constructor,Method,Filed在获取之前,我们首先来新建个一个 Test 类来供我们使用
@Data class Test { private String id; private String name; public String code; }这里需要⚠️注意,我在这里新建了两个private的字段和一个public 的字段,是为了给大家展示,即使是反射,也无法获取private的属性~
// 获取 constructor Constructor[] constructors = test.getConstructors(); Arrays.stream(constructors).forEach(System.out::println); System.out.println("------------------"); // 获取 filed Field[] fields = test.getFields(); Arrays.stream(fields).forEach(System.out::println); System.out.println("------------------"); // 获取 method Method[] methods = test.getMethods(); Arrays.stream(methods).forEach(System.out::println);打印的结果如下:
public show.shanhe.interview.reflection.Test() ------------------ public java.lang.String show.shanhe.interview.reflection.Test.code ------------------ public boolean show.shanhe.interview.reflection.Test.equals(java.lang.Object) public java.lang.String show.shanhe.interview.reflection.Test.toString() public int show.shanhe.interview.reflection.Test.hashCode() public java.lang.String show.shanhe.interview.reflection.Test.getName() public void show.shanhe.interview.reflection.Test.setName(java.lang.String) public java.lang.String show.shanhe.interview.reflection.Test.getId() public java.lang.String show.shanhe.interview.reflection.Test.getCode() public void show.shanhe.interview.reflection.Test.setCode(java.lang.String) public void show.shanhe.interview.reflection.Test.setId(java.lang.String) public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait() throws java.lang.InterruptedException public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll()在Filed的打印中,我们可以看到只有code字段被打印了出来,其余两个private的字段并没有出现在我们打印的列表中。
拿到了方法,我们就可以用反射去执行方法
Method setName = test.getMethod("setName", String.class); Test t = test.newInstance(); setName.invoke(t,"shanhe"); System.out.println(t.getName());使用Method的invoke方法,就可以去执行setName方法,这样就可以达到给对象赋值的目的~
关于反射的使用方法,到这里就告一段落,下面我们来看一下在项目中,我们如何使用反射去达到我们的目的,完成自动化的操作。
4. 反射的实际应用场景在我们的实际业务开发中,我们很少用到反射去实现我们的业务功能,因为在业务执行的过程中,我们使用反射会使代码的执行效率变得很低,所以反射一般是应用在我们设计框架的时候去使用,我们平时使用到的一些框架和技术,其底层都是基于反射去实现的,简而言之,反射是用来造轮子的,那么反射造的轮子,我们日常项目开发中经常用到的有哪些呢?
说起 Spring 的特性,大多数人脑海中浮现的的下面这两个名字,其实这两个特性都是基于反射去实现的。
AOP基于我们对 AOP 的了解,我们不难知道(如果不知道,请等待设计模式之代理模式的文章),AOP是基于动态代理去实现对方法的增强处理,那么动态代理类一般都会去继承InvocationHandler这个接口,然后通过重写接口中的invoke方法,就可以实现AOP所要达到的目的。
IOC