1.什么是类加载
类从磁盘加载到内存中经历的三个阶段: 加载,类型(验证,准备,解析),初始化。细化分的话:加载,验证,准备,解析,初始化,类型的加载,连接,初始化过程都是在程序运行期间完成的。
类型:定义的类、接口或者枚举称为类型而不涉及对象,在类加载的过程中,是一个创建对象之前的一些信息。
加载:将类的class文件中的二进制数据读取到内存中,将其放在运行时数据区的方法区中,然后在堆中生成Class对象,用来封 装 在方法区内的数据结构,并向Java程序员提供了访问方法区内的数据结构的接口。
Class对象是存放在堆区的,不是方法区,类的元数据才是存在方法区的。仔细理解为:每个new
出来的对象都是以Class
类为 模板参照出来的。
总结:类加载就是.class文件(二进制数据)——>读取到内存——>数据放进方法区——>堆中创建对应Class对象——>并提供访问方法区的接口。
2.什么是验证(了解)
为了验证确保Class文件的字节流中包含的信息符合当前虚拟机的要求
文件格式验证,元数据验证,字节码验证,符号引用验证
3.什么是准备(重点)
当完成字节码文件的校验之后,JVM 便会开始为类变量分配内存并初始化。准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些内存都将在方法区中分配。
类变量:被static修饰的变量
成员变量:其他普通变量
内存分配对象:JVM在准备阶段只会对类变量分配内存。成员变量的内存分配需要在初始化阶段开始。
至于类变量的分配何值?如果被 static final
修饰,则属性便会被赋予用户希望的值,否则赋予该数据类型的默认值。
4.什么是解析(了解)
解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。
5.什么是初始化(重点)
到了初始化阶段,用户定义的 Java 程序代码才真正开始执行。Java程序对类的使用方式可分为两种:主动使用与被动使用。一般来说只有当对类的首次主动使用的时候才会导致类的初始化
主动使用:
1. 创建类的实例,也就是new的方式
2. 访问某个类或接口的静态变量,或者对该静态变量赋值(凡是被final修饰不不不其实更准确的说是在编译器把结果放入常量池的静态字段除外)
3.调用类的静态方法
4.反射(如 Class.forName(“com.gx.yichun”))
5.初始化某个类的子类,则其父类也会被初始化
6.Java虚拟机启动时被标明为启动类的类( JavaTest ),还有就是Main方法的类会首先被初始化
6.使用和卸载
当 JVM 完成初始化阶段之后,JVM 便开始从入口方法开始执行用户的程序代码。
当用户程序代码执行完毕后,JVM 便开始销毁创建的 Class 对象,最后负责运行的 JVM 也退出内存。
7.结束生命周期
1、 执行了 System.exit()方法
2、 程序正常执行结束
3、 程序在执行过程中遇到了异常或错误而异常终止
4、 由于操作系统出现错误而导致Java虚拟机进程终止
8.接口的加载过程
当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口在初始化时,并不要求其父接口全部都完成了初始化,当真正用到父接口的时候才会初始化。
9.概念性问题
类初始化方法:编译器会按照其出现顺序,收集:类变量(static变量)的赋值语句、静态代码块,最终组成类初始化方法。类初始化方法一般在类初始化的时候执行。
对象初始化方法:编译器会按照其出现顺序,收集:成员变量的赋值语句、普通代码块,最后收集构造函数的代码,最终组成对象初始化方法,值得特别注意的是,如果没有监测或者收集到构造函数的代码,则将不会执行对象初始化方法。对象初始化方法一般在实例化类对象的时候执行。
初始化类构造器:JVM 会按顺序收集类变量的赋值语句、静态代码块,最终组成类构造器由 JVM 执行。
初始化对象构造器:JVM 会按照收集成员变量的赋值语句、普通代码块,最后收集构造方法,将它们组成对象构造器,最终由 JVM 执行。