首先Throws(抛出)几个自己学习过程中一直疑惑的问题:

1、什么是类加载?什么时候进行类加载?

2、什么是类初始化?什么时候进行类初始化?

3、什么时候会为变量分配内存?

4、什么时候会为变量赋默认初值?什么时候会为变量赋程序设定的初值?

5、类加载器是什么?

6、如何编写一个自定义的类加载器?

首先,在代码编译后,就会生成JVM(Java虚拟机)能够识别的二进制字节流文件(*.class)。而JVM把Class文件中的类描述数据从文件加载到内存,并对数据进行校验、转换解析、初始化,使这些数据最终成为可以被JVM直接使用的Java类型,这个说来简单但实际复杂的过程叫做JVM的类加载机制。

Class文件中的“类”从加载到JVM内存中,到卸载出内存过程有七个生命周期阶段。类加载机制包括了前五个阶段。

如下图所示:

其中,加载、验证、准备、初始化、卸载的开始顺序是确定的,注意,只是按顺序开始,进行与结束的顺序并不一定。解析阶段可能在初始化之后开始。

另外,类加载无需等到程序中“首次使用”的时候才开始,JVM预先加载某些类也是被允许的。(类加载的时机)

一、类的加载

我们平常说的加载大多不是指的类加载机制,只是类加载机制中的第一步加载。在这个阶段,JVM主要完成三件事:

1、通过一个类的全限定名(包名与类名)来获取定义此类的二进制字节流(Class文件)。而获取的方式,可以通过jar包、war包、网络中获取、JSP文件生成等方式。

2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。这里只是转化了数据结构,并未合并数据。(方法区就是用来存放已被加载的类信息,常量,静态变量,编译后的代码的运行时内存区域)

3、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。这个Class对象并没有规定是在Java堆内存中,它比较特殊,虽为对象,但存放在方法区中。

二、类的连接

类的加载过程后生成了类的java.lang.Class对象,接着会进入连接阶段,连接阶段负责将类的二进制数据合并入JRE(Java运行时环境)中。类的连接大致分三个阶段。

1、验证:验证被加载后的类是否有正确的结构,类数据是否会符合虚拟机的要求,确保不会危害虚拟机安全。

2、准备:为类的静态变量(static filed)在方法区分配内存,并赋默认初值(0值或null值)。如static int a = 100;

静态变量a就会在准备阶段被赋默认值0。

对于一般的成员变量是在类实例化时候,随对象一起分配在堆内存中。

另外,静态常量(static final filed)会在准备阶段赋程序设定的初值,如static final int a = 666;  静态常量a就会在准备阶段被直接赋值为666,对于静态变量,这个操作是在初始化阶段进行的。

3、解析:将类的二进制数据中的符号引用换为直接引用。

三、类的初始化

类初始化是类加载的最后一步,除了加载阶段,用户可以通过自定义的类加载器参与,其他阶段都完全由虚拟机主导和控制。到了初始化阶段才真正执行Java代码。

类的初始化的主要工作是为静态变量赋程序设定的初值。

如static int a = 100;在准备阶段,a被赋默认值0,在初始化阶段就会被赋值为100。

Java虚拟机规范中严格规定了有且只有五种情况必须对类进行初始化:

1、使用new字节码指令创建类的实例,或者使用getstatic、putstatic读取或设置一个静态字段的值(放入常量池中的常量除外),或者调用一个静态方法的时候,对应类必须进行过初始化。

2、通过java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则要首先进行初始化。

3、当初始化一个类的时候,如果发现其父类没有进行过初始化,则首先触发父类初始化。

4、当虚拟机启动时,用户需要指定一个主类(包含main()方法的类),虚拟机会首先初始化这个类。

5、使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、RE_invokeStatic的方法句柄,并且这个方法句柄对应的类没有进行初始化,则需要先触发其初始化。

注意,虚拟机规范使用了“有且只有”这个词描述,这五种情况被称为“主动引用”,除了这五种情况,所有其他的类引用方式都不会触发类初始化,被称为“被动引用”。

被动引用的例子一:

通过子类引用父类的静态字段,对于父类属于“主动引用”的第一种情况,对于子类,没有符合“主动引用”的情况,故子类不会进行初始化。代码如下:

  1. //父类
  2. public class SuperClass {
  3. //静态变量value
  4. public static int value = 666;
  5. //静态块,父类初始化时会调用
  6. static{
  7. System.out.println("父类初始化!");
  8. }
  9. }
  10. //子类
  11. public class SubClass extends SuperClass{
  12. //静态块,子类初始化时会调用
  13. static{
  14. System.out.println("子类初始化!");
  15. }
  16. }
  17. //主类、测试类
  18. public class NotInit {
  19. public static void main(String[] args){
  20. System.out.println(SubClass.value);
  21. }
  22. }

输出结果:

被动引用的例子之二:

通过数组来引用类,不会触发类的初始化,因为是数组new,而类没有被new,所以没有触发任何“主动引用”条款,属于“被动引用”。代码如下:

  1. //父类
  2. public class SuperClass {
  3. //静态变量value
  4. public static int value = 666;
  5. //静态块,父类初始化时会调用
  6. static{
  7. System.out.println("父类初始化!");
  8. }
  9. }
  10. //主类、测试类
  11. public class NotInit {
  12. public static void main(String[] args){
  13. SuperClass[] test = new SuperClass[10];
  14. }
  15. }

没有任何结果输出!

被动引用的例子之三:

刚刚讲解时也提到,静态常量在编译阶段就会被存入调用类的常量池中,不会引用到定义常量的类,这是一个特例,需要特别记忆,不会触发类的初始化!

  1. //常量类
  2. public class ConstClass {
  3. static{
  4. System.out.println("常量类初始化!");
  5. }
  6. public static final String HELLOWORLD = "hello world!";
  7. }
  8. //主类、测试类
  9. public class NotInit {
  10. public static void main(String[] args){
  11. System.out.println(ConstClass.HELLOWORLD);
  12. }
  13. }

转载,原文链接 :http://blog.csdn.net/zhangliangzi/article/details/51319033

JVM加载的初始化类的更多相关文章

  1. 全面解析JVM加载中初始化的时机

    JVM类加载过程 JVM类加载过程分为几个阶段,分别是加载.验证.准备.解析和初始化.加载是把二进制字节码载入内存,验证是校验字节流中包含的信息是否符合当要求,准备是为静态变量分配内存并设置静态变量初 ...

  2. 【JVM】查看JVM加载的类及类加载器的方法

    查看JVM加载了哪些类 java -verbose[:class|gc|jni] 在输出设备上显示虚拟机运行信息. java -verbose:class 在程序运行的时候有多少类被加载!你可以用ve ...

  3. 关于JVM加载class文件和类的初始化

    关于JVM加载class文件和类的初始化 1.JVM加载Class文件的原理机制 1.1.装载 查找并加载类的二进制数据 1.2.链接 验证:确保被加载类的正确性.(安全性考虑) 准备:为类的静态变量 ...

  4. JVM加载类的过程,双亲委派机制中的方法

    JVM加载类的过程: 1)JVM中类的整个生命周期: 加载=>验证=>准备=>解析=>初始化=>使用=>卸载  1.1.加载 类的加载阶段,主要是获取定义此类的二进 ...

  5. Java类的加载 链接 初始化

    原文地址 Java类的加载.链接和初始化.Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码到能够 ...

  6. JVM学习(二)JVM加载类

    一.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构 ...

  7. Java 类的加载与初始化

    本文结构: 1.先看几道题 2.类的加载于初始化 (1)类的加载 (2)类的初始化 (a)会发生类的初始化的情况 (b)不会发生类的初始化的情况 首先看几道题. 解析可在看完讲解后再看 Demo1 p ...

  8. <JVM中篇:字节码与类的加载篇>03-类的加载过程(类的生命周期)详解

    笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...

  9. java类的加载以及初始化顺序

    类的加载和初始化的了解对于我们对编程的理解有很大帮助,最近在看类的记载方面的问题.从网上查阅了若干文章,现总结如下: 我们通过一段代码来了解类加载和初始化的顺序: package com.classl ...

随机推荐

  1. Linux异常体系之vector_stub宏解析

    ARM-Linux汇编的宏定义语法说明如下: 使用注意: 1.宏定义以.macro开始,以.endm结束 2.可带参数,参数可有默认值 3.直接使用参数的名字\arg vector_stub宏的功能: ...

  2. Aizu - 1386 Starting a Scenic Railroad Service (思维乱搞)

    给你n个区间,求: 1:最多有多少区间与同一个区间相交. 2:相交部分的最大区间数目. Sample Input 1 4 1 3 1 3 3 6 3 6 Sample Output 1 2 2 Sam ...

  3. hdu 6333

    Problem Description There are n apples on a tree, numbered from 1 to n.Count the number of ways to p ...

  4. Selenium WebDriver-模拟鼠标双击某个元素

    #encoding=utf-8 import unittest import time import chardet from selenium import webdriver class Visi ...

  5. python - 接口自动化 - 接口测试基础知识

    # -*- coding:utf-8 -*- '''@project: jiaxy@author: Jimmy@file: study_接口测试基础知识一.py@ide: PyCharm Commun ...

  6. python week08 并发编程之多进程--理论部分

    一 什么是进程 进程:正在进行的一个过程或者说一个任务.       而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行): Jame在一个时间段内有很多任务要做:python学习任 ...

  7. js 获取data-属性值

    ].getAttribute('data-price'); 注意 document.getElementsByClassName('1pc_price')后面有[0],不然会报错.

  8. 实施生成树 STP 高级

    一.生成树协议的演化 生成树协议可以识别防止二层环路 本节介绍每VLAN快速生成树增强版 PVRST+   和多生成树MST   如何配置协议   以及配置生成树系诶稳定性机制 1.生成树协议的演化 ...

  9. Leetcode 416.分割等和子集

    分割等和子集 给定一个只包含正整数的非空数组.是否可以将这个数组分割成两个子集,使得两个子集的元素和相等. 注意: 每个数组中的元素不会超过 100 数组的大小不会超过 200 示例 1: 输入: [ ...

  10. EOJ Monthly 2018.3

    985月赛我只喜欢ECNU.jpg A. 打工时不可能打工的 Time limit per test: 2.0 seconds Memory limit: 256 megabytes 我 Ayano ...