在java代码中,类型的加载,连接,初始化过程都是在程序运行期完成的。
java.lang.ClassLoader;
类的加载和new关键字的关系:
当JVM遇到一条new指令的时候,首先先去检查这个指令的参数是否在常量池中定位能够定位到一个类的符号引用,并且检查符号引用代表的类是否已经被加载过,解析过,和初始化过;如果没有,那必须先执行相应的类加载过程,类加载检查通过后,可以说一个对象的模型已经出来了;之后就是给该对象进行内存分配任务;
ClassLoader是一个类加载器。我们的源代码经过编译器编译成字节码之后,最终都要加
载到虚拟机之后才能运行。虚拟机把描述类的数据从.class文件加载到内存,并对数据进
行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机
的类加载机制;
类加载机制的详解:
1.加载:就是将class文件加载到内存中,首先检查常量池中,类的符号引用,并检查是否已经加载过该类的Class文件,如果没有加载过,就加在改文件;
通过全限定类名来获取此类的class文件;将class文件所代表的静态存储结构转换为方法区的运行时数据结构;在java堆上生成一个代表类的class对象,作为方法区这些数据的访问入口;
2.连接: 分为三步验证,准备,解析三个阶段;
验证:就是检查该class是否完整,有没有被破坏;文件格式验证,元数据验证,字节码验证,符号引用验证;
准备:就是给静态变量分配内存空间,然后设置默认初始值为0;
在准备阶段,只会为静态变量分配内存空间,不会为成员变量分配内存空间(因为此时还没有创建对象,所以静态变量还不需要初始化)
解析:就是将常量池中的符号引用替换为直接引用;
符号引用:符号引用是用来描述所引用的目标对象,符号可以以任何形式的字面量,只要使用时定义到歧义的目标即可。引用的目标对象,并也不一定加载到内存中,java虚拟机明确在class文件格式中定义的符号引用的字面量形式;
直接引用:直接饮用可以是直接指向目标对象的指针,相对偏移量或是一个简洁定位到目标的句柄。直接引用是与虚拟机内存布局实现相关的,同一符号引用在不同的虚拟机实例上翻译出来的直接引用一般不同,如果有了直接引用,那直接饮用,必然在内存中已经存在;
如果符号引用指向一个未加载的类,或者是未被加载类的字段或方法,那么将解析的这个类的加载;
3.初始化:以上主要是由JVM直到完成的,在初始化阶段,则根据程序员通过制定的计划去初始化来变量和其他资源;在这个阶段,JVM会根据语句执行顺序对类变量进行初始化;
注意:初始化并不是创建类的实例(对象),而是执行了类的构造器,简单来说就是对类的静态变量,静态代码块进行初始化,而对构造函数只有在创建实例的时候才会执行;
类型的加载:
类型:Java源代码通过编译后的class文件;
加载:通过类加载器进行加载;将.class文件加载到JVM内存中的方法区中的数据区;
类加载器的分类:
1. 系统级别:
启动类加载器:Bootstrap ClassLoader,主要是用于加载基本类型(Java的核心类库);
负责加载JRE的核心类库,如JRE目标下的rt.jar, charsets.jar等
扩展类加载器: Extension ClassLoader,主要是用于加载标准扩展类(加载扩展类库);
负责加载JRE扩展目录ext中的jar类包
应用类加载器(APP类加载器): Application ClassLoader,用于加载classpath指定的类,以及上面没有加载的类;
负责加载Classpath路径下的类包
2. 用户级别:
自定义类加载器(继承我们的ClassLoader): User ClassLoader
负责加载用户自定义路径下的类包
3.
类加载器的加载步骤:
4. 加载:将.class文件从磁盘上读取到内存中;
6. 验证:验证字节码文件的正确性;
7. 准备:给类的静态变量分配一个内存,并赋予默认值;
8. 解析:类装载器装入类所引用的其他所有类;
9. 初始化:为类的静态变量赋予正确的初始值,上述的准备阶段为静态变量赋予的是虚拟机默认的初始值,此处赋予的是程序编写者为变量分配的真正的初始值,执行静态代码块;
10. 使用:
10.卸载: