JVM加载的初始化类
首先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的方法句柄,并且这个方法句柄对应的类没有进行初始化,则需要先触发其初始化。
注意,虚拟机规范使用了“有且只有”这个词描述,这五种情况被称为“主动引用”,除了这五种情况,所有其他的类引用方式都不会触发类初始化,被称为“被动引用”。
被动引用的例子一:
通过子类引用父类的静态字段,对于父类属于“主动引用”的第一种情况,对于子类,没有符合“主动引用”的情况,故子类不会进行初始化。代码如下:
- //父类
- public class SuperClass {
- //静态变量value
- public static int value = 666;
- //静态块,父类初始化时会调用
- static{
- System.out.println("父类初始化!");
- }
- }
- //子类
- public class SubClass extends SuperClass{
- //静态块,子类初始化时会调用
- static{
- System.out.println("子类初始化!");
- }
- }
- //主类、测试类
- public class NotInit {
- public static void main(String[] args){
- System.out.println(SubClass.value);
- }
- }
输出结果:
被动引用的例子之二:
通过数组来引用类,不会触发类的初始化,因为是数组new,而类没有被new,所以没有触发任何“主动引用”条款,属于“被动引用”。代码如下:
- //父类
- public class SuperClass {
- //静态变量value
- public static int value = 666;
- //静态块,父类初始化时会调用
- static{
- System.out.println("父类初始化!");
- }
- }
- //主类、测试类
- public class NotInit {
- public static void main(String[] args){
- SuperClass[] test = new SuperClass[10];
- }
- }
没有任何结果输出!
被动引用的例子之三:
刚刚讲解时也提到,静态常量在编译阶段就会被存入调用类的常量池中,不会引用到定义常量的类,这是一个特例,需要特别记忆,不会触发类的初始化!
- //常量类
- public class ConstClass {
- static{
- System.out.println("常量类初始化!");
- }
- public static final String HELLOWORLD = "hello world!";
- }
- //主类、测试类
- public class NotInit {
- public static void main(String[] args){
- System.out.println(ConstClass.HELLOWORLD);
- }
- }
转载,原文链接 :http://blog.csdn.net/zhangliangzi/article/details/51319033
JVM加载的初始化类的更多相关文章
- 全面解析JVM加载中初始化的时机
JVM类加载过程 JVM类加载过程分为几个阶段,分别是加载.验证.准备.解析和初始化.加载是把二进制字节码载入内存,验证是校验字节流中包含的信息是否符合当要求,准备是为静态变量分配内存并设置静态变量初 ...
- 【JVM】查看JVM加载的类及类加载器的方法
查看JVM加载了哪些类 java -verbose[:class|gc|jni] 在输出设备上显示虚拟机运行信息. java -verbose:class 在程序运行的时候有多少类被加载!你可以用ve ...
- 关于JVM加载class文件和类的初始化
关于JVM加载class文件和类的初始化 1.JVM加载Class文件的原理机制 1.1.装载 查找并加载类的二进制数据 1.2.链接 验证:确保被加载类的正确性.(安全性考虑) 准备:为类的静态变量 ...
- JVM加载类的过程,双亲委派机制中的方法
JVM加载类的过程: 1)JVM中类的整个生命周期: 加载=>验证=>准备=>解析=>初始化=>使用=>卸载 1.1.加载 类的加载阶段,主要是获取定义此类的二进 ...
- Java类的加载 链接 初始化
原文地址 Java类的加载.链接和初始化.Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码到能够 ...
- JVM学习(二)JVM加载类
一.什么是类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构 ...
- Java 类的加载与初始化
本文结构: 1.先看几道题 2.类的加载于初始化 (1)类的加载 (2)类的初始化 (a)会发生类的初始化的情况 (b)不会发生类的初始化的情况 首先看几道题. 解析可在看完讲解后再看 Demo1 p ...
- <JVM中篇:字节码与类的加载篇>03-类的加载过程(类的生命周期)详解
笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...
- java类的加载以及初始化顺序
类的加载和初始化的了解对于我们对编程的理解有很大帮助,最近在看类的记载方面的问题.从网上查阅了若干文章,现总结如下: 我们通过一段代码来了解类加载和初始化的顺序: package com.classl ...
随机推荐
- 循环字典进行操作时出现:RuntimeError: dictionary changed size during iteration的解决方案
在做对员工信息增删改查这个作业时,有一个需求是通过用户输入的id删除用户信息.我把用户信息从文件提取出来储存在了字典里,其中key是用户id,value是用户的其他信息.在循环字典的时候,当用户id和 ...
- LeetCode(129) Sum Root to Leaf Numbers
题目 Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a num ...
- C3P0连接问题
C3P0 连接时的相关问题: 我的环境是在IDEA中使用C3P0中进行的: 使用C3P0主要用到的jar包都是最新和Mysql8.0兼容的包 在连接的时候遇到: 先是在连接的时候出现数据库连接的时候的 ...
- Linux下open函数、read函数、write函数记录
open() #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> int open( cons ...
- HDU 5238 Calculator 线段树 中国剩余定理
题意: 给一个计算器,有一系列计算步骤,只有加,乘,幂三种运算. 有一种查询操作:查询初始值为\(x\)的时候,最终运算结果模\(29393\)的值. 有一种修改操作:可以修改第\(p\)个运算的运算 ...
- Leetcode31--->Next Permutation(数字的下一个排列)
题目: 给定一个整数,存放在数组中,求出该整数的下一个排列(字典顺序):要求原地置换,且不能分配额外的内存 举例: 1,2,3 → 1,3,2: 3,2,1 → 1,2,3: 1,1,5 → 1, ...
- MacOS常用软件推荐
1.效率提升神器Alfred 可以搜索文件.应用.web搜索.词典等等 链接:https://pan.baidu.com/s/1igv4tuXkuMFOPT9E6Cc5Jg 密码:3o51 软件解压密 ...
- sql server 学习分享
http://www.cnblogs.com/liu-chao-feng/p/6144872.html
- hdu5441
Travel Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Su ...
- 【Luogu】P2602数字计数(数位DP)
题目链接 数位DP好喵啊.自己yy两个小时的dfs:题解40行代码=10WA:10A. md而且还不是完全理解题解是什么意思. 所以放题解链接. #include<cstdio> #inc ...