前言
写博客也有一段时间了,之前的文章大多是工作中用到什么然后写些什么,没有什么目的性,最近一直在思考填一填之前在学习的时候留下的坑,比如说java的反射,动态代理之类的。只记得学习的时候当时老师说这是重点,反射是框架的灵魂,学习了这个才能更好的理解后面学习的框架,当时只觉的学习了个一知半解。在后面无论是工作或者学习直接面对它的机会还是比较低的,现在反过来想重新巩固一下基础,方便后续对源码的理解。
反射的机制
简单来说就是将类的各个部分封装为其他对象,这就是放射的机制。一下面的一张图来进行简单理解:
以下的三部分代表了我们写的java代码在计算机中的三个阶段,第一部分无论是我们写的java代码还是比那以后的class文件都是存在我们的硬盘当中的,它并不能运行,必须要加载到内存中才可以运行,此时通过类加载器,java中对应classLoaer这个对象,将这个class文件加载到内存中。
我们都知道Java中万物都可为对象,单拿出这一步可以理解为将这个Student对象转换为了一个Class对象,也可以说这个Class文件是用来描述加载过来的对象的。这个Class对象中存着Studen的所有信息。而这些信息是怎么存在的呢?图二中看到有这么三个数组,分别代表了成员变量,构造方法,和成员方法。没错所有属性都别封装成了这么三个数组,或者说封装成了三个对象。这也就是为什么我们在IDEA中可以“面向 . 编程”的原因 ,当我们new一个对象后,IDEA加载了这个类,而IDEA是一直在运行的,所以它可以为我们便捷的提示。这也就是代码的第三部分运行阶段。也是它的作用————可以在运行时获取对象的参数!
获取Class对象的三种方式
法一:是通过类对象来获取class的
Student student = new Student();
Class<? extends Student> aClass = student.getClass();
*法二:通过类直接调class
Class<Student> aClass = Student.class;
*法三:通过Class.forName();
Class<?> aClass = Class.forName("com.xxx.xxx.xxx.Student");
一般都推荐使用第三种方法,降低耦合度
通过Class获取构造方法
//获取所有的构造方法(包括私有、受保护、默认、公有)
public Constructor[] getConstructors();
//获取单个的"公有的"构造方法
public Constructor getConstructor(Class... parameterTypes);
//获取"某个构造方法"可以是私有的,或受保护、默认、公有
Constructor getDeclaredConstructor(Class... parameterTypes);
通过Class获取成员变量
//获取所有的"公有字段"
Field[] getFields();
//获取所有字段,包括:私有、受保护、默认、公有
Field[] getDeclaredFields();
//获取某个"公有的"字段
public Field getField(String fieldName);
//获取某个字段(可以是私有的)
public Field getDeclaredField(String fieldName);
//设置字段的值
public void set(Object obj,Object value);
通过Class获取成员方法
//获取所有的"公有方法"
Method[] getMethods();
//获取所有方法,包括:私有、受保护、默认、公有
Field[] getDeclaredMethods();
//获取某个"公有的"字段,var2代表形参类型
Method getMethod(String var1, Class<?>... var2);
//获取某个字段(可以是私有的),var2代表形参类型
public Method getDeclaredMethod(String var1, Class<?>... var2);
//运行方法
//前面的操作仅仅是获取到了方法,并不是真正的调用,如果想要运行该方法还应该调用Method中的这个方法
//var1是类的对象,var2是形参
public Object invoke(Object var1, Object... var2);
//补充使用Class创建对象,newInstance是 Constructor类的方法,可以理解为使用该方法来代替,Class类所解释的方法的构造器来创建对象
public T newInstance();