type
status
date
slug
summary
tags
category
icon
password
反射的概念
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并直接操作任意对象的内部属性及方法。
框架 = 反射 + 注解 + 设计模式
体会反射的动态性
反射机制可以提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行是构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运营时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
相关API
- java.lang.Class:反射的源头
- java.lang.reflect.Method
- java.lang.reflect.Field
- java.lang.reflect.Constructor

Class类的理解
- 类的加载过程:
- Class的实例就对应着一个运行时类。
- 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式 来获取此运行时类。
类的加载过程
- 调用 javac.exe 命名将 .java 编译生成为 .class字节码文件!生成的字节码文件在硬盘里,没有被加载到内存中 在 IDEA里通过 build-->要编译的项目/模块/类
- 类在什么情况下会被加载:
- 使用类创建对象
- 使用反射操作类
- 调用类里的静态方法,访问静态属性。但如果访问的是类里的静态成员常量,这个类不会被初始化
- 子类初始化之前也会先初始化父类
- 运行main方法所在的类也会加载
3. 类是由 类加载器ClassLoader加载到内存中的

类加载器
类加载器作用是用来加载一个类,不同的类使用的类加载器有区别
- JAVA内置核心库里的类,由 BootstrapClassLoader 来加载 String.java, System.java等文件编译以后生成的 .class 文件在 Java_HOME/JRE/lib/rt.jar包 JavaDevelopmentKit Java开发工具集 JavaRuntimeEnvironment Java运行环境
运行一个代码,不一定需要 .java 文件,只需要有 .class字节码文件 和 JRE就能启动java程序。BootstrapClassLoader不是由Java语言写的,由C/C++写的,使用 Java代码获取不到
- JAVA的扩展类库,由 ExtClassLoader 来加载 扩展类库位置: JAVA_HOME/JRE/lib/ext 文件夹下,所有的 .jar包
- 程序员自己写的 .java文件编译成的 .class文件,由 AppClassLoader 来加载
同时还可以自定义类加载器

类加载器的作用

创建类的对象方式
- new + 构造器
- 看类中是否存在静态方法可以返回一个实例对象
- 反射
获取类加载器的方法
- 类对象.getClassLoader()
- ClassLoader.getSystemClassLoader()也能获取到一个 AppClassLoader
获取类对象的四种方式
- 类名.class 获取到类对象
- 调用 实例对象.getClass() 方法获取到类对象
- Class.forName(String className);
- 使用类加载器来加载一个类
用反射读取文件的注意事项
使用类加载器或者类对象读取文件的前提是: 文件必须要被编译到 out文件夹下
创建一个和 src 同级的文件夹 config,怎样将文件夹编译到 out目录里:
右键 config文件夹 --> mark directory as --> 选择 sourcesRoot或者resourcesRoot
- 使用 类加载器 获取到IO流:(推荐使用) 从当前模块编译后所在的 out文件夹 <项目名>/out/production/Day21
- 使用 类对象 获取到IO流: 参考使用类对象所在的包
使用反射获取构造方法
- getConstructors(): 获取到所有被public修饰的构造方法
- getConstructor(Class<T>... paramTypes): 根据参数的类型获取到指定的被public修饰的构造方法
- getDeclaredConstructors(): 获取到所有的构造方法,包括被private/protected/缺省修饰的构造方法
- getDeclaredConstructor(Class<T>...paramTypes): 根据参数的类型获取到指定的构造方法
用反射获取类里声明的方法
- getMethods(): 获取到所有被public修饰的方法,包括父类里声明的public方法
- getMethod(String methodName,Class<T>...paramTypes):根据方法名和参数获取到指定的方法
- getDeclaredMethods(): 获取到本类里所有的方法,包括被private/protected以及缺省修饰的方法
- getDeclaredMethod(String methodName,Class<T>...paramTypes)
通过反射获取成员变量
getFields() / getField(String fieldName)
getDeclaredFields() / getDeclaredField(String fieldName)
创建运行时类的对象
newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。
要想此方法正常的创建运行时类的对象,要求:
- 运行时类必须提供空参的构造器
- 空参的构造器的访问权限得够。通常,设置为public。
在javabean中要求提供一个public的空参构造器。原因:
- 便于通过反射,创建运行时类的对象
- 便于子类继承此运行时类时,默认调用super()时,保证父类此构造器
获取运行时类的完整结构
我们可以通过反射,获取对应的运行时类中所有的属性、方法、构造器、父类、接口、父类的泛型、包、注解、异常等
获取运行时类的指定结构
代理模式
使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
- 静态代理:
- 静态代理的缺点
- 代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。
- 每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。
动态代理
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
- 动态代理需要解决的两个主要问题
- 如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。(通过Proxy.newProxyInstance()实现)
- 当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。 (通过InvocationHandler接口的实现类及其方法invoke())
- 作者:tacjin
- 链接:http://jin.wiki/article/69f26726-db30-484d-a4c4-b08a480645ad
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。