Java类的生命周期 与 类加载器
1、简介
Java 虚拟机为 Java 程序提供运行时环境, 其中一项重要的任务就是管理类和对象的生命周期。类的生命周期从类被加载、连接、初始化开始,到类被卸载结束。当类处于生命周期中时,它的二进制数据位于方法区内,在方法区还会有一个相应的描述这个类的Class对象,只有当类处于生命周期中时,Java程序才能使用它,比如调用类的静态属性和方法,或者创建类的实例。
2、类的加载、连接、初始化
- 加载: 查找并加载类的二进制数据(把类的 .class文件读取到内存中),把他存放到运行时数据区的方法区内。
- 连接: 包括验证(确保被加载的类的正确性)、准备(为类的静态变量分配内存,并将其初始化)和 解析类(把类中的 符号引用 转换成 直接引用)的二进制数据 。
- 初始化: 每个类或接口被 java 程序主动使用的时候才会初始化。如果类存在直接的父类,并且父类还没有被初始化,那就先初始化父类。
3、类的初始化时机
- 创建类的实例。
- 调用类的静态方法。
- 访问某个类或接口的静态变量, 或者对静态变量赋值。
- 调用Java API中某些反射方法,比如:Class.forName("Test")。 (调用ClassLoader类的loadClass()方法加载一个类不会导致初始化。)
- 初始化一个类的子类。
4、类加载器
类加载器用来把类加载到Java 虚拟机中。从JDK1.2开始,类的加载采用父亲委托机制,这种机制能更好的保证Java平台的安全。除了Java 虚拟机自带的根类加载器外(没有父加载器), 其余的类加载器都只有一个父类加载器,当Java 程序请求load1去加载Sample 类时, load1首先委托父加载器去加载,若父加载器能加载, 则由父加载器加载, 否则由load1本身去加载。
Java 虚拟机自带的几种类加载器:
- 根(Bootstrap)类加载器: 加载虚拟机的核心类库, 如 java.lang.*。 由虚拟机实现, 没有继承 java.lang.ClassLoader类。
- 扩展(Extension)类加载器: 它的父加载器是根类加载器。 它负责从: java.ext.dirs 系统属性所指定的类库或从 JDK安装的目录:jre\lib\ext子目录下加载类库。如果把用户创建的Jar文件放在这个目录下,也会自动有扩展类加载器加载。扩展类加载器是纯Java类加载器, 是java.lang.ClassLoader的子类。
- 系统(System)类加载器: 也称为应用类加载器, 它的父加载器是扩展类加载器。它从环境变量 classpass 或系统属性:java.class.path 所制定的目录中加载类。他是用户自定义类加载器的默认父加载器,系统类加载器是纯Java类, 是java.lang.ClassLoader的子类。
5、类的卸载
当 Sample类被加载、连接和初始化后, 它的生命周期就开始了,当代表Sample类的 Class 对象不再被引用时, 即不可触及, Class对象的生命周期就会结束。Sample类在方法区的数据也会被卸载。从而结束Sample 类的生命周期。前面介绍的 Java 虚拟机自带的类加载器所加载的类,在虚拟机的生命周期中始终不会被卸载。Java 虚拟机会始终引用这些类加载器,而这些类加载会始终引用它们所加载的类的Class对象, 因此这些类始终是可及的。
一个类的实例总时引用代表这个类的 Class 对象,在 Object 类中定义了 getClass()方法, 这个方法返回代表对象所属类的Class对象的引用。此外所有的Java类都有一个静态属性 class, 它引用代表这个类的class对象,例如:
// c1 引用代表Sample类的Class对象
Class c1 = Sample.class;
// c2 引用代表Sample类的Class对象
Class c2 = new Sample().getClass()
// c3 引用代表Sample类的Class对象
Class c3 = Class.forName("Sample")
c1= c2 = c3 = true