java的类加载机制

一、什么是类加载机制:

将类的.class文件中的二进制数据读到内存中,并将其放入方法区中,在堆中创建一个java.lang.Class对象,这个对象用来封装方法区内的数据。

加载.class文件的方式:

1、本地系统中直接加载

2、将java源文件动态编译为.class文件

3、从专有库中提取.class文件

4、从zip、jar等文件中加载.class文件

5、从网络下载.class文件

二、类的生命周期:

类加载的过程包括了 加载、验证、准备、解析、初始化五个阶段。

加载(获取类的二进制字节流的动作):

加载需要做的三件事:

1、通过一个类的全限定名来获取其定义的二进制字节流

2、将这个字节流的静态存储结构转换为方法区的运行时数据结构

3、在堆生成一个代表这个类的java.lang.Class对象作为方法区中这些数据的访问入口

连接(分为验证、准备、解析)

验证:确保被加载的类的正确性(重要但不是必须的,-Xverifynone参数来关闭大部分的类验证措施)

    文件格式验证:验证字节流是否符合Class文件格式的规范

    元数据验证:对字节码描述的信息进行语义分析

    字节码验证:通过数据流和控制流分析,确保程序语义是合法且符合逻辑的

    符号引用验证:确保解析动作能正确执行

准备:为类的静态变量分配内存(都在方法区分配),并将其初始化为默认值

    这个时候进行内存分配的仅包括类变量(static),不包括实例变量,实例变量会在对象实例化时随着对象一起分配在java堆中-------->什么是类变量和实例变量?什么是局部变量和全局变量?

类变量:也叫静态变量,在类前加了static的变量

实例变量:也叫对象变量,在类前没有加static的变量

类变量是针对所有对象共有的,一个对象改变其值后,其他对象得到的是改变后的值;实例变量属于对象私有,一个对象改变其值后,不影响其他对象。

全局变量:也叫成员变量,在类中定义的变量,不需要先赋值,系统会赋默认值

局部变量:在方法中定义的变量,使用前需要先赋值,否则编译不通过

针对同时被static和final修饰的常量,必须在声明时就为其显示赋值,否则编译不通过;而只被final修饰的常量则既可以在声明时显式地为其赋值,也可以在类初始化时显式地为其赋值,总之,在使用前必须为其显式地赋值,系统不会为其赋予默认零值。

    这里所设置的初始值通常情况下是数据类型默认的零值(如0、0L、null、false等),而不是被在Java代码中被显式地赋予的值。

解析:把类中的符号引用转换为直接引用

        符号引用:一组符号来描述目标,可以是任何字面量

        直接引用:直接指向目标的指针、相对偏移量或一个间接定位到目标的句柄

初始化:为类的静态变量赋予正确的初始值,主要有两种方式

1、声明变量时指定初值

2、使用静态代码块为类变量指定初值

JVM初始化步骤:

    假设这个类还没有被加载和连接,则程序先加载并连接该类

    假设该类的直接父类还没有被初始化,则先初始化其直接父类

    假设类中有初始化语句,则系统依次执行这些初始化语句

类初始化的时机:

    创建类的实例,即new的方式

    访问某个类或接口的静态变量,或者对该静态变量赋值

    调用类的静态方法

    反射

    初始化某个类的子类,则其父类也会被初始化

    java虚拟机启动时被标明为启动类的类(java Test),直接使用java.exe命令来运行某个主类

三、三类类加载器

启动类加载器:Bootstrap Classloader,负责加载放在JDK\jre\lib(JDK表示JDK的安装目录)目录下,或者被-Xbootclasspath参数指定路径中的能被虚拟机识别的类库(所有java.开头的都能被启动类加载器加载)

扩展类加载器:Extension Classloader,负责加载JDK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的所有类库(如javax.开头的类)

应用程序加载器:Application Classloader,负责加载用户路径(ClassPath)所指定的类

四、类的加载

三种类加载方式:

1、命令行启动应用时由JVM初始化加载

2、通过Class.forName()方法动态加载

3、通过ClassLoader.loadClass()方法动态加载

Class.forName()与ClassLoader.loadClass()的区别

Class.forName()会将类的.class文件加载到jvm中,同时对类进行解释,执行类中的static块;ClassLoader.loadClass()不会执行static块。

五、双亲委派模式

    一个加载器收到了类加载的请求,它首先不会自己去加载该类,而是把这个类请求父加载器去加载,依次向上,当父加载器无法加载时,子加载器才会去加载。

eg:

1、当 AppClassLoader加载一个class时,它首先不会自己去尝试加载这个类,而是把类加载请求委派给父类加载器ExtClassLoader去完成。

2、当 ExtClassLoader加载一个class时,它首先也不会自己去尝试加载这个类,而是把类加载请求委派给BootStrapClassLoader去完成。

3、如果 BootStrapClassLoader加载失败(例如在 $JAVA_HOME/jre/lib里未查找到该class),会使用 ExtClassLoader来尝试加载;

4、若ExtClassLoader也加载失败,则会使用 AppClassLoader来加载,如果 AppClassLoader也加载失败,则会报出异常 ClassNotFoundException。

你可能感兴趣的:(java的类加载机制)