什么是反射
反射是一种让Java拥有一定动态性的机制,它允许程序在执行期间取得任何类的内部信息,并且直接操作任意对象的内部属性及方法
类加载
类加载后通过堆内存方法区的Class类型对象就能了解该类的结构信息,这个对象就像该类的一面镜子,通过这面镜子能够看到类的所有结构(无论是不是private的),所以称之为反射
某类需要被使用时,如果还未加载,系统会通过类的加载、类的连接和类的初始化三步来准备类,统称为类加载或类初始化
1. 加载:将class文件读入内存,创建一个java.lang.Class对象(任何类被使用时都会有)
2. 连接:验证内部结构,为类变量分配内存并赋默认值,将二进制数据的符号引用转为直接引用
3. 初始化:对类变量初始化(从祖宗类开始),如果类有初始化语句就依次执行
反射能做什么
在运行时
- 判断对象的类
- 构造任一类的对象
- 判断任一类的成员变量和方法
- 获取泛型信息
- 调用任一对象的成员变量和方法
- 处理注解
- 动态代理
它可以动态创建对象和编译,但是反射实时给JVM需求会比直接操作慢
反射获取Class对象
用Class.forName()
方法通过反射直接获取test包下Dog类的Class对象
Class cls = Class.forName("test.Dog");
用object.getClass()
方法通过反射借助Dog类实例获取Dog类的Class对象
Class cls2 = (new Dog()).getClass();
用类名.class int[ ]也算
Class cls3 = Dog.class;
通过反射获得类的结构
调用缺省构造函数,返回Class对象的一个实例
Object istc = cls.newInstance();
获得该Class对象的实体(类,接口,数组类,void)名称
String name = cls.getName();
获得父类Class对象
Class<?> clsParent = cls.getSuperClass();
获得接口Class对象的数组
Class<?>[] Its = cls.getInterfaces();
获得该类的类加载器
ClassLoader cld = cls.getClassLoader();
获得该类Constructor对象的数组
Constructor[] constructors = cls.getConstructors();
获得一个Method对象,此对象形参为paramType
Method m = cls.getMethod(.......)
获得所有的Field属性/方法/构造器数组
Field[] fields = cls.getDeclaredFields();
Method[] methods = cls.getDeclaredMethods();
Constructor[] constructors = cls.getDeclaredConstructors();
获取public的属性/方法/构造器
Field[] fields = cls.getFields();
Method[] methods = cls.getMethods();
Constructor[] constructors = cls.getConstructors();
获取指定属性/方法/构造器
Field = cls.getField("name");
Method method1 = cls.getMethod("getName", null);
Method method2 = cls.getMethod("setName", String.class);
Constructor constructor = cls.getConstructor(String.class, int.class);//参数类型
类加载器(了解)
负责将.class文件加载入内存,并生成对应java.lang.Class对象
加载器机制:
- 全盘负责:加载某个类时其关联的其他Class也由同一加载器加载
- 父类委托:先让父类加载器加载,如果无法加载才自己加载
- 缓存机制:缓存被加载过的Class,先找缓存,找不到再加载类二进制数据转换成Class对象并缓存
加载器类型:
- Bootstrap根类加载器,jvm内置加载器,不属于ClassLoader谱系,底层是C++,对开发者透明
- Plantform class loader平台类加载器,负责Java SE API的实现类和JDK特定运行时类
- System class loader应用程序类加载器,如果没有特别指定,则用户自定义的类加载器都以此类加载器作为父加载器。
类加载器流程
- 检测此Class是否载入过,即在缓冲区中是否有此Class,如果有直接进入第8步,否则进入第2步。
- 如果没有父类加载器,则要么Parent是根类加载器,要么本身就是根类加载器,则跳到第4步,如果父类加载器存在,则进入第3步。
- 请求使用父类加载器去载入目标类,如果载入成功则跳至第8步,否则接着执行第5步。
- 请求使用根类加载器去载入目标类,如果载入成功则跳至第8步,否则跳至第7步。
- 当前类加载器尝试寻找Class文件,如果找到则执行第6步,如果找不到则执行第7步。
- 从文件中载入Class,成功后跳至第8步。
- 抛出ClassNotFountException异常。
- 返回对应的java.lang.Class对象。
获取泛型
获取注解
看文档