JVM学习四:JVM之类加载器之初始化分析
在经过了前面的加载 和 连接分析之后,这一节我们进入重要的初始化分析过程:

一、认识初始化
初始化:这个似乎与上面的初始化为默认值有点矛盾,我们再看一遍:为累的静态变量赋予正确的初始值,上面是赋予默认值,这里是赋予正确的初始值,什么是正确的初始值,就是用户给赋予的值。我们来看一个例子
class Test{
private static int a = 1;
}
我们知道,这个类加载好之后,a的值就是1,但实际是这样子的,类在加载的连接阶段,将a初始化为默认值0(int的默认值是0),然后在初始化阶段将a的值赋予为正确的初始值1. 我们看到最终a的值是等于1,但是实际的运行中是有一个将0赋予a的过程,这个过程放生在连接的准备阶段。类的初始化还有另外的一种形式,代码如下:
class Test{
private static int a ;
static{
a=1;
}
}
这里强调一点,这个时候还是没有类的实例生成的,这点一定要注意!《深入java虚拟机第二版》里面有一个图阐述了对应的关系,如下:

静态变量的声明语句,以及静态代码块都被看做类的初始化语句,Java虚拟机会按照初始化语句在类文件中的先后顺序来依次执行它们。
二、初始化步骤
1.假如这个类还没有被加载和连接,那就先进行加载和连接。【加载和连接执行完成后不一定会执行初始化,要符合主动使用才会进行初始化,否则只会执行加载和连接】
2.假如类存在直接的父类,并且这个父类还没有被初始化,那就先初始化直接的父类。
3.假如类中存在初始化语句,那就依次执行这些初始化语句。
三、主动使用和被动使用【初始化时机】
Java程序对类的使用方式可分为2种,主动使用和被动使用。所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用时”才初始化他们。
主动使用的六种情况:
1.创建类的实例。
new Test();
2.访问某个类或接口的静态变量,或者对该静态变量赋值。
int b = Test.a;
Test.a = b;
3.调用类的静态方法
Test.doSomething();
4.反射
Class.forName(“com.mengdd.Test”);
5.初始化一个类的子类
class Parent{
}
class Child extends Parent{
public static int a = 3;
}
Child.a = 4;
6.Java虚拟机启动时被标明为启动类的类
java com.mengdd.Test
除了以上六种情况,其他使用Java类的方式都被看作是对类的被动使用,都不会导致类的初始化 (除了上述6种情况以外,都不会执行初始化,只会执行加载和连接)

这个时候我们再来看第一节学习中那段比较诡异的代码:
class Singleton{
private static Singleton singleton=new Singleton();
private static int counter1;
private static int counter2 = 0;
public Singleton() {
counter1++;
counter2++;
}
public static int getCounter1() {
return counter1;
}
public static int getCounter2() {
return counter2;
}
public static Singleton getInstance(){
return singleton;
}
}
public class ClassLoaderTest {
@SuppressWarnings("static-access")
public static void main(String[] args) {
Singleton singleton=Singleton.getInstance();
System.out.println("counter1:"+singleton.getCounter1());
System.out.println("counter2:"+singleton.getCounter2());
System.out.println(singleton.getClass().getClassLoader());
}
}
我们调用Singleton singleton=Singleton.getInstance();调用Singleton的静态方法,相当于主动使用了类Singleton,因此Singleton被初始化!
当我们看到显示的是:
private static Singleton singleton=new Singleton();
private static int counter1;
private static int counter2 = 0;
这样的时候,顺序执行,先赋予初始值,singleton为null,counter1为0,counter2为0,然后顺序对singleton赋予正确的值newSingleton(),执行构造函数,counter1增加变为1,然后counter2变为1,然后继续执行初始化,将counter2赋值为正确的值,将counter2修改为0,因此运行结果是1、0
反过来
private static int counter1;
private static int counter2 = 0;
private static Singleton singleton=new Singleton();
先赋予初始值counter1为0,counter为0,singleton为null,然后对counter2赋值为正确的值,counter2为0,然后对singleton执行初始化赋予正确的值new Singleton(),执行构造函数,counter1为1,counter2为1,因此执行结果是1、1
到此,是不是感觉前面的问题豁然开朗了呢?
参考资料:
圣思园张龙老师深入Java虚拟机系列
JVM学习四:JVM之类加载器之初始化分析的更多相关文章
- jvm系列(四):jvm知识点总结
原文链接:http://www.cnblogs.com/ityouknow/p/6482464.html jvm 总体梳理 jvm体系总体分四大块: 类的加载机制 jvm内存结构 GC算法 垃圾回收 ...
- jvm学习006 jvm内存结构分配
主要内容如下: JVM启动流程 JVM基本结构 内存模型 编译和解释运行的概念 一.JVM启动流程: JVM启动时,是由java命令/javaw命令来启动的. 二.JVM基本结构: JVM基本结构图: ...
- JVM学习笔记-JVM模型
JVM学习笔记 == 标签(空格分隔): jvm 学习笔记全部来自于<深入理解java虚拟机>总结 jvm内存示意图 虚拟机栈(Java Virtual Machine Stacks): ...
- JVM学习三:JVM之类加载器之连接分析
学习完类加载之加载篇后,让我们继续来看加载之连接,连接分为三个步骤:验证.准备和解析三步,我们将一一分析之. 连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去. 类加载完毕之后进入 ...
- JVM学习四:深入分析ClassLoader
一.什么是ClassLoader? 大家都知道,当我们写好一个Java程序之后,不是管是CS还是BS应用,都是由若干个.class文件组织而成的一个完整的Java应用程序,当程序在运行时,即会调用该程 ...
- JVM体系结构之二:类加载器之2:JVM 自定义的类加载器的实现和使用
一.回顾一下jdk自带的类加载器: 1.java虚拟机自带的加载器 根类加载器(Bootstrap,c++实现) 扩展类加载器(Extension,java实现) 应用类加载器 ...
- 【JVM学习笔记】系统类加载器
可以通过“java.system.class.loader"属性指定系统类加载器 默认情况下,该属性值为空: public class Test { public static void m ...
- 【JVM学习笔记】扩展类加载器
扩展类加载器独有的特点,代码如下 public class Sample { } public class Test { static { System.out.println("Test ...
- JVM学习--(四)垃圾回收算法
我们都知道java语言与C语言最大的区别就是内存自动回收,那么JVM是怎么控制内存回收的,这篇文章将介绍JVM垃圾回收的几种算法,从而了解内存回收的基本原理. stop the world 在介绍垃圾 ...
随机推荐
- 软件定义网络(SDN)研究进展
写在前面 这是我入门SDN以来的第一篇论文,它是一篇中文综述,看起来相对容易.也让我对SDN有了进一步的认识.下面是我的一些心得. 全文框架 SDN 将数据平面与控制平面解耦合,简化了网络管理. SD ...
- ubuntu关闭系统自动检测错误
sudo gedit /etc/default/apport 将enabled=1 改成 enabled=0
- HttpWebRequest下载文件,乱码问题解决方案
写在前面 今天之所以会总结HttpWebRequest下载文件,主要是因为在使用该类下载文件的时候,有些地方需要注意一下,在实际的项目中遇到过这种问题,觉得还是有必要总结一下的.在下载文件时,最常见的 ...
- 解释Spring中IOC, DI, AOP
oc就是控制翻转或是依赖注入.通俗的讲就是如果在什么地方需要一个对象,你自己不用去通过new 生成你需要的对象,而是通过spring的bean工厂为你长生这样一个对象.aop就是面向切面的编程.比如说 ...
- Hbase的安装和配置
1,准备好hbase的linux环境下的压缩包,这里hadoop版本为hadoop2.5.0,hbase版本为 2,解压缩这个版本,不选src的,其实两个任一都行 进入到hbase安装包目录,我这里的 ...
- (十一)Jmeter另一种调试工具 HTTP Mirror Server
之前我介绍过Jmeter的一种调试工具Debug Sampler,它可以输出Jmeter的变量.属性甚至是系统属性而不用发送真实的请求到服务器.既然这样,那么HTTP Mirror Server又是做 ...
- Halcon 笔记1
Halcon Example位置: C:\Users\Public\Documents\MVTec\HALCON-13.0\examples 安装位置:C:\Program Files\MVTec\H ...
- VSS2005设置不输入密码直接登录VSS
1.登录管理员 2.Tools-->Options-->General -->Use network name for automatic user log in 去掉勾选不自动登 ...
- 【刷题】BZOJ 4199 [Noi2015]品酒大会
Description 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品酒家"和"首席猎手&quo ...
- 【BZOJ4152】The Captain(最短路)
[BZOJ4152]The Captain(最短路) 题面 BZOJ Description 给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求 ...