Skip to content

反射与模块化

一、类加载器

1、类加载

1)类加载方式

JVM通过类的加载,类的连接,类的初始化对类进行初始化

类的加载:class文件读入内存,创建java.lang.Class对象

2)类的连接

验证:检验类

准备:分配内存,设置默认初始化值

解析:二进制数据中的符号引用替换为直接引用

3)类的初始化

对类变量进行初始化

类没被加载或连接 --> 先加载并连接

父类为初始化 --> 初始化直接父类(最先初始化Object类)

类中有初始化语句 --> 执行初始化语句

2、类的初始化时机

  1. 创建对象,调用方法
  2. 初始化子类
  3. java.exe命令运行主类
  4. 反射创建类或接口的java.lang.Class对象

3、类加载器的作用

将.class加载到内存,生成java.lang.Class对象

4、JVM的类加载机制

全盘负责:加载类及其相关类

父类委托:让父类加载器加载

缓存机制:用过的类有缓存

5、加载器分类

Bootstrap class loader:内置类加载器,通常表示为null

Platform class loader:平台类加载器,加载api、运行时类

System class loader:应用程序类加载器,定义应用程序路径、模块路径

6、ClassLoader类方法

  1. static classLoader getSystemClassLoader():返回用于委派的系统类加载器
  2. ClassLoader getParent():返回父类加载器进行委派

二、反射概述

1、反射

通过类加载器加载的.class文件对象的Class类进行调用

反射是框架设计的灵魂

框架:半成品软件。可以在框架基础上进行软件开发,简化编码

2、反射机制

将类的各个组成部分封装成其他对象

3、反射优点

  1. 可以在程序运行中操作对象 idea
  2. 可以解耦,提高程序可扩展性

4、Java代码的三个阶段

  1. Source源代码:*.java ->(javac编译) *.class
  2. Class类对象:*.class ->(ClassLoader类加载器) class类对象
  3. Runtime运行阶段:创建对象

三、获取class对象的方式

1、Class.forName()

Source源代码阶段:Class.forName("包名.类名");

Class类的静态方法

将字节码文件加载进内存,返回class对象

2、类名.class

Class类对象阶段:类名.class

通过类名的属性返回class对象

3、对象.getClass()

Runtime运行阶段:对象.getClass()

定义在Object类中

同一个字节码文件(*.class)在一次程序运行中只会加载一次

四、Class对象功能

1、获取成员方法

java
Field[] getFields()					//获取所有public修饰成员
File getField(String name)			//获取指定名称public修饰成员
    
Field[] getDeclaredFields()			//获取所有的成员
File getDeclaredField(String name)	//获取指定名称的成员

Field成员变量:

  1. 设置值:void set(Object obj, Object value)
  2. 获取值:get(Object obj)

暴力反射(忽略权限修饰符的安全检查):变量对象.setAccessible(true);

2、获取构造方法

java
Constructor<?>[] getConstructor()
Constructor<T> getConstructor(类<?>... parameterTypes)	//指定构造方法的参数 String.class int.class ...
    
Constructor<?>[] getDeclaredConstructor()
Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)

Constructor构造方法:Object obj = 构造方法对象.newInstance(构造)

3、获取成员方法

java
Method[] getMethods()
Method getMethods(String name, 类<?>... parameterTypes
    
Method[] getDeclaredMethods()
Method getDeclaredMethods(String name, 类<?>... parameterTypes)

Method方法对象:

  1. 执行方法:方法对象.invoke(Object obj, Object...args);
  2. 获取方法名:String getname()

4、获取类名

java
String getName()

五、越过泛型检查

java
List<Integer> list = new ArrayList<>();
list.add(123);
Method m = list.getClass().getMethod("add", Object.class);
m.invoke(list,"hello");
System.out.println(list);

六、运行配置文件的指定方法

properties
className=...
methodName=...
java
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推出模块化

  1. 在模块的scr目录下新建module-info.java的描述文件
  2. 对于导出模块:exports 包名;
  3. 对于导入模块:requires 包名;

八、模块服务的使用

1、导出模块

描述文件:provides 接口名 with 实现类

2、导入模块

1、描述文件:uses 接口名

2、加载服务:ServiceLoader<接口名> 变量名 = ServiceLoader.Load(导出模块名.class);

3、遍历服务:

java
for(接口名 变量名2 : 变量名){
    变量名2.接口内的方法();	// 实现其模块实现类的方法
}

Released under the MIT License.