一、整个加载过程:
- Java虚拟机动态加载,链接和初始化类和接口。
- 加载 是查找具有特定名称的类或接口类型的二进制表示形式并从该二进制表示形式_创建_类或接口的过程。
- 链接 是获取类或接口并将其组合到Java虚拟机的运行时状态以便可以执行的过程。
- 类或接口的初始化包括执行类或接口的初始化方法
Java虚拟机启动
Java虚拟机通过使用引导类加载器创建一个初始类来启动,该类以与实现相关的方式指定。然后,Java虚拟机将链接初始类,对其进行初始化,然后调用public
class方法void main(String[])
。该方法的调用将推动所有进一步的执行。构成该main
方法的Java虚拟机指令的执行可能会导致其他类和接口的链接(并因此创建),以及其他方法的调用。
在Java虚拟机的实现中,可以将初始类作为命令行参数提供。或者,该实现可以提供一个初始类,该初始类设置了一个类加载器,该类加载器又加载了一个应用程序。初始类的其他选择也是可能的,只要它们与上一段中给出的规范一致即可。
1.1、Loading 装载
1.1.1: 先找到classw文件 ---> 字节流 ---> 类加载器ClassLoader
(1)分类:
启动类加载器/Bootstrap ClassLoader
在HotSpot虚拟机中,Bootstrap ClassLoader用C++语言编写并嵌入JVM内部,主要负载加载`JAVA_HOME/lib`目录中的所有类,或者加载由选项`-Xbootcalsspath`指定的路径下的类;
拓展类加载器/ExtClasLoader
ExtClassLoader继承ClassLoader类,负载加载`JAVA_HOME/lib/ext`目录中的所有类型,或者由参数`-Xbootclasspath`指定路径中的所有类型;
应用程序类加载器/AppClassLoader
ExtClassLoader继承ClassLoader类,负责加载用户类路径`ClassPath`下的所有类型,一般情况下为程序的默认类加载器;
自定义加载器
Java虚拟机规范将所有继承抽象类java.lang.ClassLoader的类加载器,定义为**自定义类加载器**;
测试:
public static void main(String[] args) {
System.out.println(new Student().getClass().getClassLoader());
System.out.println(new Student().getClass().getClassLoader().getParent());
System.out.println(new Student().getClass().getClassLoader().getParent().getParent());
System.out.println(new String().getClass().getClassLoader());
}
sun.misc.Launcher$AppClassLoader@18b4aac2
sun.misc.Launcher$ExtClassLoader@10f87f48
null
null
(2)重点:双亲委派原则
1. 定义(ClassLoader原话):
The <tt>ClassLoader</tt> class uses a delegation model to search for classes and resources. Each instance of <tt>ClassLoader</tt> has an associated parent class loader. When requested to find a class or resource, a <tt>ClassLoader</tt> instance will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself. The virtual machine's built-in class loader, called the "bootstrap class loader", does not itself have a parent but may serve as the parent of a <tt>ClassLoader</tt> instance.
意思是:ClassLoader用的是委派模型去搜索类和资源,ClassLoader每个实例都有一个关联的父类加载器,当请求查找类或资源时, ClassLoader实例会将对类或资源的搜索委托给其父类加载器,然后再尝试查找类或资源本身。虚拟机的内置类加载器(称为“引导类加载器”)本身没有父级,但可以用作ClassLoader实例的父级。
2. 关键作用:
当程序中出现两个类名形同的类时,比如:自定义一个String类,自定的String的类加载器通过双亲委派原则会交个父类加载(启动类加载器),当父类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载网络传递的过来的java.lang.String,而直接返回已加载过的IntStringeger.class,这样便可以防止核心API库被随意篡改。
3. JDBC、Tomcat中为什么要破坏双亲委派模型:
问题简单描述:
1、双亲委派原则中,当父类加载不到该资源,就会委派给子类去加载;
2、当被加载的类引用了另外一个类,那么类加载器就会用加载第一个类的加载器去加载被引用的类
那么问题来了,当子类加载器加载的类引用了一个父类加载器加载的类,按理说,这两个类都会被子类加载器加载,很明显,子类加载器是加载不到父类加载器中的类,那么子类会加载不成功
[https://www.javazhiyin.com/44347.html](https://www.javazhiyin.com/44347.html)
1.1.2: 字节流 ---> 静态数据结构 ---> 方法区(供所有Java虚拟机栈使用)
1.1.3: 字节流 ---> class对象 ---> 堆 (供所有Java虚拟机栈使用)
1.2、Linking 链接
- Verification 验证
验证数据的准确性。说白了就是看你文件对不对,例:文件格式、元数据、字节码、符号引用 - Preparation 准备
为类的静态变量分配内存,并赋值为当前类型默认值; - Resolution 解析
将类的符号引用(存在常量池)变成直接引用;
这在class文件汇总只是表示改数据是什么类型,就如一种标识、一种符号,在这个过程中要将这些符号分配内存
1.3、Initiating 初始化
为类的静态变量真正的初始化值
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。