1.如下几种情况,将导致JVM结束生命周期:
1)执行了System.exit()方法
注意exit()参数的意义
2)程序正常执行结束
3)程序在执行过程中遇到了异常或错误而异常终止
4)由于操作系统出现错误而导致Java虚拟机进程终止
2.一些概念,类的加载、连接、初始化
加载:查找并加载类的二进制数据
连接:
验证:确保被加载的类的正确性
准备:为类的静态变量分配内存,并将其初始化为默认值
解析:把类中的符号引用转换为直接引用
初始化:为类的静态变量赋予正确的初始值(指的是用户赋予的初始值,不是默认的)
-所有的JVM实现必须在每个类或接口被Java程序“首次主动使用”时初始化他们
3.Java程序对类的使用方式分为两种:
主动使用
被动使用
3.1主动使用:
1)创建类的实例
注意,对象声明不是主动使用
2)访问某个类或接口的静态变量,或者对该静态变量赋值
3)访问类的静态方法
4)反射
Class.forName("xxxx");
5)初始化一个类的子类,也看作对父类的主动使用
6)JVM启动时被标明为启动类的类(Java Test)
3.2被动使用
除了前面六种,对java类的使用是被动使用,不会导致类的初始化
4.类的加载
-类的加载指的是将类的.class文件中的二进制数据读入到内存中,
将其放在运行时数据区的方法区内,
然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构
*类的加载的最终产品是位于堆区中的Class对象,
Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区的数据结构的接口
*无论为类创建多少个实例,他的Class对象都只有一个
*Class是整个java反射的一个入口,封装了类在方法区内的数据结构
*加载器加载的是类,而不是对象
4.1加载.class文件的方式
1)从本地系统中直接加载
2)通过网络下载.class文件
URLClassLoader
3)从zip,jar等归档文件中加载.class文件
4)从专有数据库中提取.class 文件
5)将Java源文件动态编译为.class文件
4.2类加载器
-JVM自带的加载器:
根类加载器Bootstrap,C++
扩展类加载器Extension, Java
系统类加载器System(应用加载器),Java
-用户自定义的类加载器
java.lang.ClassLoader的子类
用户可以定制类的加载方式
clazz.getClassLoader()
返回null的情况
类加载器的选用
5.类的连接
类加载后,就进入了连接阶段。
连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行环境中去
5.1.类的验证
1)类文件的结构检查
2)语义检查
3)字节码验证
4)二进制兼容性的验证
5.2类的准备
JVM为类的静态变量分配内存,并设置默认的初始值。
5.3类的解析
符号引用->直接引用(指针,地址)
java从使用阶段(对java程序员)来说,是没有指针的。但其实是有指针的
6.类的初始化
JVM执行类的初始化语句,为类的静态变量赋予初始值
6.1两种途径:
1)在静态变量的声明处进行初始化
2)在静态代码块中进行初始化
6.2类的初始化步骤:
1)假如这个类没有被加载和连接,就先加载和连接
2)假如类存在直接的父类,并且这个父类没有被初始化,就先初始化父类
3)假如类中存在初始化语句,就依次执行这些初始化语句
*直接访问类的静态常量不会导致类的初始化,直接访问类的静态变量会导致类的初始化
public static final int x = new Random().nextInt(100);
and
public static final int x = 6/3;
*所谓的对类进行初始化和不对类进行初始化,区别就是否运行类的静态代码块
*只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类的或接口的主动使用。怎么理解呢?
如果访问的静态方法或静态变量在父类中定义的,则 即使通过子类去访问这些变量或方法,也不认为是对子类的主动使用,不会导致子类的初始化;而是对相应父类的主动使用
6.3当JVM初始化一个类时,要求它的所有的父类都已经被初始化,但是这条规则不适用于接口
一个父接口不会因为他的 子接口 或者 实现它的类 的初始化而初始化,只有当程序首次使用特定接口的静态变量时,才会导致该接口的初始化
7.类加载器
7.1类加载器的父亲委托机制-Parent Delegation
7.2类加载器的使用
1)根加载器:
*该加载器没有父加载器
*负责加载虚拟机的核心库,eg.java.lang.*
*根加载器从系统属性sun.boot.class.path所指定的目录中加载类库
*根加载器的实现依赖于底层操作系统,属于虚拟机实现的一部分,没有继承java.lang.ClassLoader类
2)扩展类加载器:
*父加载器是根类加载器
*从系统属性java.ext.dirs指定的目录中加载类库
或者从JDK的安装目录的jre\lib\ext子目录下加载类库
*纯Java类,是java.lang.ClassLoader的子类
3)系统类加载器-应用加载器
*父加载器是扩展类加载器
*从环境变量classpath或者系统属性java.class.path指定的目录中加载类
*是用户自定义的类加载器的默认父加载器
*纯Java类,是java.lang.ClassLoader的子类
7.3
*类加载器的父子关系,不同于类实现结构上的继承关系
*定义类加载器:如果某个类加载器能够加载一个类,那么该类加载器称作:定义类加载器
定义类加载器及其所有子加载器都称作:初始类加载器
*当生成一个自定义的类加载器实例时,如果没有指定它的父加载器,那么系统类加载器就成为该类加载器的父加载器
7.4不同类加载器的命名空间关系
1)同一个命名空间内的类是相互可见的
2)子加载器的命名空间包含所有父加载器的命名空间。
因此由子加载器加载的类能看见父加载器加载的类。
eg.系统类加载器加载的类能看见根类加载器加载的类
3)由父加载器加载的类不能看见子加载器加载的类
4)如果两个加载器之间没有直接或间接的父子关系,那么他们各自加载的类相互不可见
5)通过反射可以突破命名空间的限制
8类的卸载
一个类被加载、连接、初始化后,他的生命周期即开始
一个类的Class对象不再被引用,即不可触及时,Class对象就会结束生命周期,这个类在方法区内的数据也会被卸载,从而结束这个类的生命周期
一个类何时结束生命周期,取决于代表它的Class对象何时结束生命周期
*由JVM自带的类加载器加载的类,在虚拟机的生命周期中,始终不会被卸载。始终可触及。
JVM会始终引用这些类加载器,这些类加载器始终会引用它们所加载的类的Class对象。
*由用户自定义的类加载器所加载的类是可以卸载的