JVM 类加载过程
在Java代码中,类型的加载、连接与初始化过程都是在程序运行期间(Runtime)完成的。
**类的加载:**查找并记载类的二进制数据
**类的连接:**验证——确保被加载的类的正确性
准备——为类的静态变量分配内存,并将其初始化为默认值
解析——把类中的符号引用转换为直接引用
类的初始化:为类的静态变量赋予正确的初始化
类加载的过程:
加载:
找到字节码文件,读取到内存中.类的加载方式分为隐式加载和显示加载两种。隐式加载指的是程序在使用new关键词创建对象时,会隐式的调用类的加载器把对应的类加载到jvm中。显示加载指的是通过直接调用Class.forName()方法来把所需的类加载到jvm中。
验证:
验证此字节码文件是不是真的是一个字节码文件,毕竟后缀名可以随便改,而内在的身份标识是不会变的.在确认是一个字节码文件后,还会检查一系列的是否可运行验证,元数据验证,字节码验证,符号引用验证等.Java虚拟机规范对此要求很严格
准备:
为类中static修饰的变量分配内存空间并设置其初始值为0或null.可能会有人感觉奇怪,在类中定义一个static修饰的int,并赋值了123,为什么这里还是赋值0.因为这个int的123是在初始化阶段的时候才赋值的,这里只是先把内存分配好.但如果你的static修饰还加上了final,那么就会在准备阶段就会赋值.
解析:
解析阶段会将java代码中的符号引用替换为直接引用.比如引用的是一个类,我们在代码中只有全限定名来标识它,在这个阶段会找到这个类加载到内存中的地址
初始化:
这个阶段就是对变量的赋值的阶段.
ps:同一个类,如果使用的是不同的类加载器加载的,那么最后使用instanceof会返回一个false
双亲委派机制:
向上委派向下加载
JVM的生命周期
JVM的生命周期大致分为以下三个阶段:
JVM实例的诞生
当启动一个Java程序时,一个JVM实例就产生了,任何一个拥有 public static void main(String[] args) 函数的class都可以作为JVM实例运行的起点
JVM实例的运行
main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以标明自己创建的线程是守护线程。java程序的初始线程 只就是运行main()的线程,这个线程是非守护线程,只要还有任何非守护线程还在运行,那么JVM就存活着
JVM实例的消亡
当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用 java.lang.Runtime 类或者 java.lang.System.exit() 来退出
Java类的生命周期
当我们编写一个java的源文件后,经过编译会生成一个后缀名为class的文件,这种文件叫做字节码文件,只有这种字节码文件才能够在java虚拟机中运行,**java类的生命周期就是指一个class文件从加载到卸载的全过程。**一个java类的完整的生命周期会经历加载、连接、初始化、使用、和卸载五个阶段,当然也有在加载或者连接之后没有被初始化就直接被使用的情况,大致过程如下图所示:
Java程序对类的使用方式分为两种:
1.主动使用
2.被动使用
所有的Java虚拟机实现必须在每个类或者接口被Java程序“首次主动使用”才能初始化他们。
主动使用(七种):
1.创建类的实例
2.访问某个类或者接口的静态变量,或对该静态变量赋值。(静态变量的取值或者赋值)getstatic、putstatic(助记符)
3.调用类的静态方法。invokestatic
4.反射(如 Class.forName (“com.ylw.Test”))。
5.初始化一个类的子类
6.Java虚拟机启动时被标名为启动类的类(包含main方法)。
7.JDK1.7开始提供的动态语言支持:java.lang.invok.MethodHandle 实例的解析结果 REF_getStatic, REF_putStatic, REF_invokeStatic 句柄对应的类没有初始化则初始化。
ps: 除了以上七种情况,其他使用java类的方式都被看做是对类的被动使用,都不会导致类的初始化。

