类加载器
类加载器的作用和加载时机
-
作用 : 负责将.class文件(存储的物理文件)加载在到内存中
-
加载时机 : 用到即加载
- 创建类的实例(对象)
Student stu = new Student();
- 调用类的静态方法
Arrays.toString(arr);
- 访问类或者接口的静态变量,或者为该类静态变量赋值
interface Inter { int NUM = 10; } System.out.println(Inter.NUM); ------------------------------------------------------------------------------ class A { public static int num; } A.num = 20; System.out.println(A.num);
- 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
Class clazz = Class.forName("com.itheima.domain.Student"); clazz.newInstance();
- 初始化继承体系
class Fu {} class Zi extends Fu {} Zi z = new Zi(); 1). Zi 字节码文件 2). Fu 字节码文件
- 直接使用 java.exe 命令来运行某个主类
java HelloWorld.java
类加载器的过程
加载:通过包名+类名,获取这个类,准备用流进行传输,将类加载到内存中,加载完毕创建一个class对象
验证:检验文件中的信息是否符合虚拟机规范,有没有安全隐患
准备:为类的类变量(被static修饰的变量)分配内存,设置默认初始化值()初始化静态变量
解析:将类的二进制数据流中符号引用替换为直接引用 (本类中如果用到了其他类,此时就需要找到对应的类)
初始化:静态变量赋值以及初始化其他资源
小结
- 当一个类被使用的时候,才会加载到内存
- 类加载的过程: 加载、验证、准备、解析、初始化
类加载器的分类
类的字节码对象.getClassLoader(); 获取该类的, 类加载器对象.
- Bootstrap class loader:虚拟机的内置类加载器,通常表示为null
- C++ 实现, 获取到的只能是 null
- Platform class loader:平台类加载器,负责加载JDK中一些特殊的模块 负责加载 lib\modules 内部的类
- JDK9 之前是 :(Extension Class Loader) 扩展类加载器 : 负责加载 jre\lib\ext 目录下的类
- Application class loader:负责加载自己写的类
- 自定义类加载器 : 上级为 Application
- 目前不做讲解 , 自己设计框架的时候才会用得到
双亲委派机制
如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行,如果父类加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终将到达顶层的启动类加载器,如果父类加载器可以完成类加载任务,就成功返回,倘若父类加载器无法完成此加载任务,子加载器才会尝试自己去加载,这就是双亲委派模式
好处 :
- 双亲委派模型保证了 Java 程序的稳定运行,可以避免类的重复加载
- 当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次
- 保证了 Java 的核心 API 不被篡改
假设我们自己编写了一个 Object 类
1. java.lang.Object类 (真的)
2. java.lang.Object类 (假的)
双亲委派模型可以保证加载的是 JRE 里的那个 Object 类, 而不是我们自己写的
AppClassLoader ---> PlatformClassLoader ---> BootstrapClassLoader
BootstrapClassLoader : 发现已经加载过了Object类了, 就不会加载我们自己写的了
常用方法
方法名 | 作用 |
---|---|
public static ClassLoader getSystemClassLoader() | 获取系统类加载器 |
public InputStream getResourceAsStream(String name) | 加载某一个资源文件 |
public static void main(String[] args) throws Exception {
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("config.properties");
Properties prop = new Properties();
prop.load(is);
is.close();
//通过配置文件获取全类名
String className = prop.getProperty("className");
Class<?> aClass = Class.forName(className);
System.out.println(aClass);*/
Class<?> aClass = Class.forName("com.Student");
//反射空参构造方法(解剖)
Constructor<?> constructor = aClass.getConstructor();
//使用空参构造方法对象,构造对象
Object o = constructor.newInstance();
//反射带参构造方法(解剖)
Constructor<?> constructor1 = aClass.getConstructor(String.class);
Object o2 = constructor1.newInstance("张三");
//[暴力反射]带参构造方法(解剖)
Constructor<?> constructor2 = aClass.getDeclaredConstructor(String.class);
//开启权限
constructor2.setAccessible(true);
Object o3 = constructor2.newInstance("王飞杨");
}
}
tructor(String.class);
//开启权限
constructor2.setAccessible(true);
Object o3 = constructor2.newInstance("王飞杨");
}
}