类加载的时机
-
类的生命周期
- 加载
- 连接
- 验证
- 准备
- 解析
- 初始化
- 使用
- 卸载
-
虚拟机规定必须初始化
- 遇到new getstatic putstatic invokestatic 四个字节码指令,如果类没有初始化,则需要先触发初始化。
- 使用场景
- 使用new 关键字 实例化对象
- 读取或者设置一个类的静态字段
- 调用一个类的静态方法的时候
- 使用场景
- 使用java.lang.reflect 包的方法对类进行反射调用的时候
- 初始化一个类的时候,发现其父类还没有初始化,则触发父类的初始化
- 当虚拟机启动的时候,用户需要制定一个要执行的主类(main) 虚拟机会先初始化这个类
- 当使用JDK 1.7的动态语言支持时,如果-个java.lang.invoke.MehodHandle实例最后的解析结果REF_ getStatic、 REF_ putStatic、 invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。
- 这五种初始化称为对一个类的主动引用
- 遇到new getstatic putstatic invokestatic 四个字节码指令,如果类没有初始化,则需要先触发初始化。
加载
- 加载的过程
- 通过一个类的全限定名来获取定义此类的二进制字节流
- 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
- 在内存中生成一个代表这个类的java.lang.Class对象 作为方法区这个类的各种数据的访问入口
验证
- 连接的第一步,确保class文件的字节流都符合虚拟机的要求,而且不会危害虚拟机的安全.
- 过程
- 文件格式验证
- 元数据验证
- 字节码验证
- 符号引用验证
准备
- 正式为类变量分配内存并且设置类变量初始化的阶段,这些变量所使用的内存都将在方法区中进行分配(static 变量)
解析
- 虚拟机将常量池内的符号引用替换成直接引用
- 符号引用
- 用一组符号来表示所引用的对象,符号可以是任何形式的字面量,只要使用时可也准确的定位到目标。
- 引用的目标不一定已经加载到内存中
- 直接引用
- 可以是直接指向目标的指针,相对偏移量或者是一个能间接定位到目标的句柄。同一个符号引用在不同虚拟机实例上翻译出来的直接引用一般不会相同,如果有了直接引用,那么引用的目标必定已经在内存中存在。
- 符号引用
初始化
- 真正执行类中定义的java程序代码( 字节码)
- 因为准备阶段,变量已经赋过一次系统要求的初始值。而初始化阶段 则根据程序员通过程序制定的主关计划去初始化类变量和其他资源。
- 初始化过程就是执行类构造器()方法的过程.
- ()方法由编译器自动收集类中的所有类变量的赋值动作和静态语句块中的语句合并产生的,编译收集的顺序是源文件中出现的顺序。
- ()与类的构造器不同,它不需要显式地的调用父类构造器,虚拟机会保证子类的()执行之前,父类的()已经执行完毕。因此第一个执行()的一定是Object类
- 由于父类的()方法先执行,所以父类中定义的静态语句快要优先子类的变量赋值操作。
- ()方法对于类或者接口来说不是必须的,如果一个类没有静态语句快 也没有对变量的赋值过程,那么编译器可以不为这个类产生()方法。
- 接口中不能使用静态语句快,但任然有变量初始化的赋值操作,因此接口和类一样都会生成()方法,但是接口和类不同的是,执行接口的()方法不需要先执行父接口的()方法。
- 虚拟机会保证一个类的()方法在多线程环境中被正确的加锁、同步。
类加载
-
通过一个类的全限定名在获取描述此类的二进制字节流 的这个类被称为 类加载器。
-
对于任意一个类,都需要由加载他的加载器和类本身来确地在虚拟机中的唯一性。
-
双亲委派模型
- 类加载器
- 启动类加载器(Bootstrap ClassLoader)
- 主要负责加载 存放<java_home>\lib 中的或者被-Xbootclasspath参数所指定的目录。
- 启动类加载器无法被java程序直接引用,使用null 代替.
- 扩展类加载器(Extension ClassLoader)
- 负责加载<java_home>\lib\ext 目录的
- 可以直接使用
- 应用程序类加载器
- 又称系统类加载器
- 负责加载用户类路径上的指定的类库。
- 默认的
- 启动类加载器(Bootstrap ClassLoader)
- 工作过程
- 如果一个类加载器收到了类加载的请求,它首先不会自己尝试去加载这个类,而是把这个请求委派给父类加载器去完成,每一层加载器都是如此,因此最后所有的加载请求都传送到顶层的启动类加载器。只有当父加载器反馈自己无法完成这个加载请求,子加载器才会尝试自己去加载。
- 好处
- java类随着它的类加载器一起具备了带优先级的层次关系。
- 避免类的重复加载
- 保护程序安全,防止核心API 被随意篡改
- 类加载器