1、类加载过程
类加载:类加载器将class文件加载到虚拟机内存
- 加载:在硬盘上查找并通过IO读入字节码文件
- 连接:执行校验、准备、解析(可选)步骤
- 校验:校验字节码文件的正确性
- 准备:给类的静态变量分配内存,并赋予默认值
- 解析:类装载器装入类所引用的其他所有类
- 初始化:对垒的静态变量初始化为指定的值,执行静态代码块
2、类加载器种类
- 引导类加载器:负责加载JRE的核心类库,如jre目标下的rt.jar,charsets.jar等
- 扩展类加载器:负责加载JRE扩展目录ext中的JAR类包
- 系统类加载器:负责加载ClassPath路径下的类包
- 用户自定义加载器:负责加载用户自定义路径下的类包
示例代码如下:
public class TestClassLoader {
public static void main(String[] args) {
System.out.println(String.class.getClassLoader());
System.out.println(com.sun.crypto.provider.DESKeyFactory.class.getClassLoader().getClass().getName());
System.out.println(TestClassLoader.class.getClassLoader().getClass().getName());
System.out.println(ClassLoader.getSystemClassLoader().getClass().getName());
}
}
/*
null String是在rt.jar中,并且rt.jar是由c++编写不在jdk中,因此无法打印
sun.misc.Launcher$ExtClassLoader DESKeyFactory是在ext.jar包的类,因此是由扩展类加载器实现的
sun.misc.Launcher$AppClassLoader 负责加载ClassPath路径下的类包
sun.misc.Launcher$AppClassLoader
3、类加载机制
- 全盘负责委托机制:当一个ClassLodaer加载一个类时,除非显示的使用另一个ClassLoader,该类所依赖和引用的类也有这个ClassLoader载入
- 双亲委派机制:指先委托父类加载器寻找目标类,在找不到的情况下在自己的路径中查找并载入目标类(一般情况下是用不到自定义类加载器的)
2)举例:
一个类在加载的时候不会先加载,会向上委托由当前类加载器的上级看是否可以加载,如果不可以加载再向上委托,当引用类加载器无法加载时,才会由下级类加载器加载3)优点
- 沙箱安全机制:自己写的String.class不会被加载,这样会防止核心API被随意篡改
- 避免类的重复加:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次
4)代码示例:
这里我们可以自己来写一个String.class来做测试,我们运行会发现提示找不到main方法。此处我们可以使用上述类加载机制来解释这个原因,我们自定义的Sting类时在当前的Classpath路径下,应该由系统类加载器加载。由于双亲委派机制,此类会先委托给上级加载直到引导类加载器。引导类加载的是在rt.jar包中的String.class而不是我们自定义的类。
public class String {
public static void main(String[] args) {
System.out.println("测试沙箱安全机制");
}
}
4、jvm在加载jar包是否会将包里的所有的类全都加载到内存中?
JVM对class文件是按需加载(运行期间动态加载,而不是一次性加载),可以配置-verbose:class参数来验证