day16-类加载器与反射
一:类加载器
1.1 类加载器的作用
类加载器就是将编译好的字节码文件加载到内存中运行
1.2 类加载的时机
创建类的对象
调用类的类方法(类方法就是静态方法)
访问类或者接口类的变量,或者为该类变量赋值
初始化某个类的子类
直接使用java.exe运行java文件
使用反射技术强制创建某个类或者接口对应的class对象
用到就加载,不用就不加载
1.3 类加载的过程
- 加载
- 通过全类名获取这个类的二进制字节流,准备用流进行传输,将字节码文件加载到内存中,当一个类加载完毕之后都会创建该类的class对象
- 链接
- 验证:文件中有没有不符合虚拟机的内容,确保不会伤害到虚拟机自身安全
- 准备:负责为静态变量(类的类变量)分配内存,并赋给初始值
- 解析:将符号引用找到实际直接的引用,本类中用到了其他的类就需要找到这个类
- 初始化
1.4 类加载器的分类
- 启动类加载器(BootStrap ClassLoader),虚拟机内置的类加载器,底层是C++
- 平台类加载器(Platform ClassLoader),负责加载JDK中特殊的模块
- 系统类加载器(System ClassLoader),负责加载用户路径上所指定的类库
1.5 双亲委派模型及常用方法
1.5.1 双亲委派模型
双亲委派模型工作过程是:如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时(即ClassNotFoundException
),子加载器才会尝试自己去加载。
1.5.2 ClassLoader中常用的两个方法
方法名 | 说明 |
---|---|
public static ClassLoader getSystemClassLoader() | 获取系统类加载器 |
public InputStream getResourceAsStream(String name) | 加载某一个资源文件 |
public static void main(String[] args) throws IOException {
// 获取系统类加载器
ClassLoader classLoader = ClassLoader.getSystemClassLoader();
// 通过获取的系统类加载器加载指定文件,获得一个字节流对象
InputStream is = classLoader.getResourceAsStream("log4j.properties");
// 将前两步简化
InputStream isPlus = ClassLoader.getSystemResourceAsStream("log4j.properties");
// 通过转换流转换为字符流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
// 读写操作
String line;
while ((line = br.readLine()) != null){
System.out.println(line);
}
br.close();
}
二:反射
2.1 反射概述
是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意属性和方法;
这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
2.2 获取class对象的三种方式
- Class.forName(全类名)方法 -> (源代码阶段)
- 类名.class属性 ->(对象阶段)
- 对象名.getClass()方法 ->(runtime运行阶段)
2.3 反射获取构造方法并使用
2.3.1 反射获取构造方法Constructor
方法名 | 说明 |
---|---|
Constructor<?>[] getConstructors() | 返回所有公共构造方法对象的数组 |
Constructor<?>[] getDeclaredConstructors() | 返回所有构造方法对象的数组 |
Constructor getConstructor(Class<?>… parameterTypes) | 返回单个公共构造方法对象 |
Constructor getDeclaredConstructor(Class<?>… parameterTypes) | 返回单个公共构造方法对象 |
2.3.2 反射创建对象
方法名 | 说明 |
---|---|
T newInstance(Object…initargs) | 根据指定的构造方法创建对象 |
setAccessible(boolean flag) | 设置为true,表示取消访问检查 |
- 注意点:如果要通过反射获取非public修饰的构造方法创建对象,必须先取消访问检查
2.4 反射获取成员变量并使用
2.4.1 反射获取成员变量Field
方法名 | 说明 |
---|---|
Field[] getFields() | 返回所有公共成员变量对象的数组 |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组 |
Field getField(String name) | 返回单个公共成员变量对象 |
Field getDeclaredField(String name) | 返回单个成员变量对象 |
2.4.2 反射给成员变量赋值
方法名 | 说明 |
---|---|
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 获取值 |
- 注意点:不管是赋值还是获取值都要指定对象;
2.5 反射获取成员方法并使用
2.5.1 反射获取成员方法Method
方法名 | 说明 |
---|---|
Method[] getMethods() | 返回所有公共成员方法对象的数组,包括继承的 |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,不包括继承的 |
Method getMethod(String name, Class<?>… parameterTypes) | 返回单个公共成员方法对象 |
Method getDeclaredMethod(String name, Class<?>… parameterTypes) | 返回单个成员方法对象 |
2.5.2 使用反射获取的成员方法
方法名 | 说明 |
---|---|
Object invoke(Object obj, Object… args) | 运行方法 |
2.6 反射总结
- 通过反射不管是获取构造方法,成员变量,成员方法,首先必须获取其class对象