反射与模块化
一、类加载器
1、类加载
1)类加载方式
JVM通过类的加载,类的连接,类的初始化对类进行初始化
类的加载:class文件读入内存,创建java.lang.Class对象
2)类的连接
验证:检验类
准备:分配内存,设置默认初始化值
解析:二进制数据中的符号引用替换为直接引用
3)类的初始化
对类变量进行初始化
类没被加载或连接 --> 先加载并连接
父类为初始化 --> 初始化直接父类(最先初始化Object类)
类中有初始化语句 --> 执行初始化语句
2、类的初始化时机
- 创建对象,调用方法
- 初始化子类
- java.exe命令运行主类
- 反射创建类或接口的java.lang.Class对象
3、类加载器的作用
将.class加载到内存,生成java.lang.Class对象
4、JVM的类加载机制
全盘负责:加载类及其相关类
父类委托:让父类加载器加载
缓存机制:用过的类有缓存
5、加载器分类
Bootstrap class loader:内置类加载器,通常表示为null
Platform class loader:平台类加载器,加载api、运行时类
System class loader:应用程序类加载器,定义应用程序路径、模块路径
6、ClassLoader类方法
static classLoader getSystemClassLoader()
:返回用于委派的系统类加载器ClassLoader getParent()
:返回父类加载器进行委派
二、反射概述
1、反射
通过类加载器加载的.class文件对象的Class类进行调用
反射是框架设计的灵魂
框架:半成品软件。可以在框架基础上进行软件开发,简化编码
2、反射机制
将类的各个组成部分封装成其他对象
3、反射优点
- 可以在程序运行中操作对象 idea
- 可以解耦,提高程序可扩展性
4、Java代码的三个阶段
- Source源代码:*.java ->(javac编译) *.class
- Class类对象:*.class ->(ClassLoader类加载器) class类对象
- Runtime运行阶段:创建对象
三、获取class对象的方式
1、Class.forName()
Source源代码阶段:Class.forName("包名.类名");
Class类的静态方法
将字节码文件加载进内存,返回class对象
2、类名.class
Class类对象阶段:类名.class
通过类名的属性返回class对象
3、对象.getClass()
Runtime运行阶段:对象.getClass()
定义在Object类中
同一个字节码文件(*.class)在一次程序运行中只会加载一次
四、Class对象功能
1、获取成员方法
Field[] getFields() //获取所有public修饰成员
File getField(String name) //获取指定名称public修饰成员
Field[] getDeclaredFields() //获取所有的成员
File getDeclaredField(String name) //获取指定名称的成员
Field成员变量:
- 设置值:
void set(Object obj, Object value)
- 获取值:
get(Object obj)
暴力反射(忽略权限修饰符的安全检查):变量对象.setAccessible(true);
2、获取构造方法
Constructor<?>[] getConstructor()
Constructor<T> getConstructor(类<?>... parameterTypes) //指定构造方法的参数 String.class int.class ...
Constructor<?>[] getDeclaredConstructor()
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
Constructor构造方法:Object obj = 构造方法对象.newInstance(构造)
3、获取成员方法
Method[] getMethods()
Method getMethods(String name, 类<?>... parameterTypes
Method[] getDeclaredMethods()
Method getDeclaredMethods(String name, 类<?>... parameterTypes)
Method方法对象:
- 执行方法:
方法对象.invoke(Object obj, Object...args);
- 获取方法名:
String getname()
4、获取类名
String getName()
五、越过泛型检查
List<Integer> list = new ArrayList<>();
list.add(123);
Method m = list.getClass().getMethod("add", Object.class);
m.invoke(list,"hello");
System.out.println(list);
六、运行配置文件的指定方法
className=...
methodName=...
Properties prop = new Properties();
prop.load(new FileReader("xxx.txt"));
Class<?> c = Class.forName(prop.getProperty("className"));
Method m =c.getMethod(prop.getProperty("methodName"));
Object obj = c.newInstance();
m.invoke(obj);
七、模块化使用
Java9推出模块化
- 在模块的scr目录下新建
module-info.java
的描述文件 - 对于导出模块:
exports 包名;
- 对于导入模块:
requires 包名;
八、模块服务的使用
1、导出模块
描述文件:provides 接口名 with 实现类
2、导入模块
1、描述文件:uses 接口名
2、加载服务:ServiceLoader<接口名> 变量名 = ServiceLoader.Load(导出模块名.class);
3、遍历服务:
for(接口名 变量名2 : 变量名){
变量名2.接口内的方法(); // 实现其模块实现类的方法
}