上接深入java虚拟机——深入java虚拟机(二)——类加载器详解(上),在上一篇文章中,我们讲解了类的生命周期的加载和连接,这一篇我们接着上面往下看。

类的初始化:在类的生命周期执行完加载和连接之后就开始了类的初始化。在类的初始化阶段,java虚拟机执行类的初始化语句,为类的静态变量赋值,在程序中,类的初始化有两种途径:(1)在变量的声明处赋值。(2)在静态代码块处赋值,比如下面的代码,a就是第一种初始化,b就是第二种初始化

  1. public class Test
  2. {
  3. public static int a = 0;
  4. public static int b ;
  5. static{
  6. b=2;
  7. }
  8. }

静态变量的声明和静态代码块的初始化都可以看做静态变量的初始化,类的静态变量的初始化是有顺序的。顺序为类文件从上到下进行初始化,想到这,想起来一个很无耻的面试题,分享给大家看一下:

  1. package com.bzu.csh;
  2. class Singleton
  3. {
  4. private static Singleton singleton = new Singleton();
  5. public static int counter1;
  6. public static int counter2 = 0;
  7. private Singleton()
  8. {
  9. counter1++;
  10. counter2++;
  11. }
  12. public static Singleton getInstance()
  13. {
  14. return singleton;
  15. }
  16. }
  17. public class Test
  18. {
  19. public static void main(String[] args)
  20. {
  21. Singleton singleton = Singleton.getInstance();
  22. System.out.println("counter1 = " + singleton.counter1);
  23. System.out.println("counter2 = " + singleton.counter2);
  24. }
  25. }

大家先看看这里的程序会输出什么?

不知道大家的答案是什么,如果不介意的话可以把你的答案写到评论上,看看有多少人的答案和你一样的。我先说说我刚开始的答案吧。我认为会输出:

counter1 = 1

Counter2 = 1

不知道大家的答案是不是这个,反正我的是。下面我们来看一下正确答案:

不知道你做对没有,反正我刚开始做错了。好,现在我来解释一下为什么会是这个答案。在给出解释之前,我们先来看一个概念:

Java程序对类的使用方式可分为两种

主动使用

被动使用

•所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”时才初始化他们

主动使用(六种)

–创建类的实例

–访问某个类或接口的静态变量,或者对该静态变量赋值

–调用类的静态方法

–反射(如Class.forName(“com.bzu.csh.Test”))

–初始化一个类的子类

–Java虚拟机启动时被标明为启动类的类(Java Test)

OK,我们开始解释一下上面的答案,程序开始运行,首先执行main方法,执行main方法第一条语句,调用Singleton类的静态方法,这里调用Singleton类的静态方法就是主动使用Singleton类。所以开始加载Singleton类。在加载Singleton类的过程中,首先对静态变量赋值为默认值,

Singleton=null

counter1 = 0

Counter2 = 0

给他们赋值完默认值值之后,要进行的就是对静态变量初始化,对声明时已经赋值的变量进行初始化。我们上面提到过,初始化是从类文件从上到下赋值的。所以首先给Singleton赋值,给它赋值,就要执行它的构造方法,然后执行counter1++;counter2++;所以这里的counter1 = 1;counter2 = 1;执行完这个初始化之后,然后执行counter2的初始化,我们声明的时候给他初始化为0 了,所以counter2 的值又变为了0.初始化完之后执行输出。所以这是的

counter1 = 1

counter2 = 0

类初始化步骤

(1)假如一个类还没有被加载或者连接,那就先加载和连接这个类

(2)假如类存在直接的父类,并且这个父类还没有被初始化,那就先初始化直接的父类

(3)假如类中存在初始化语句,那就直接按顺序执行这些初始化语句

在上边我们我们说了java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”时才初始化他们,上面也举出了六种主动使用的说明。除了上述六种情形,其他使用Java类的方式都被看作是被动使用,不会导致类的初始化。程序中对子类的“主动使用”会导致父类被初始化;但对父类的“主动”使用并不会导致子类初始化(不可能说生成一个Object类的对象就导致系统中所有的子类都会被初始化)

注:调用ClassLoader类的loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化。

当java虚拟机初始化一个类时,要求它的所有的父类都已经被初始化,但这条规则并不适用于接口。

在初始化一个类时,并不会先初始化它所实现的接口

在初始化一个接口时,并不会先初始化它的父接口

因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化。只有当程序首次使用特定接口的静态变量时,才会导致该接口的初始化。只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类或接口的主动使用 。如果是调用的子类的父类属性,那么子类不会被初始化。

[Java]类的生命周期(下)类的初始化[转]的更多相关文章

  1. java 静态变量生命周期(类生命周期)

    Static: 加载:java虚拟机在加载类的过程中为静态变量分配内存. 类变量:static变量在内存中只有一个,存放在方法区,属于类变量,被所有实例所共享 销毁:类被卸载时,静态变量被销毁,并释放 ...

  2. java 静态变量生命周期(类生命周期)(转)

    Static: 加载:java虚拟机在加载类的过程中为静态变量分配内存. 类变量:static变量在内存中只有一个,存放在方法区,属于类变量,被所有实例所共享 销毁:类被卸载时,静态变量被销毁,并释放 ...

  3. 乐字节Java反射之三:方法、数组、类加载器和类的生命周期

    本文承接上一篇:乐字节Java发射之二:实例化对象.接口与父类.修饰符和属性 继续讲述Java反射之三:方法.数组.类加载器 一.方法 获取所有方法(包括父类或接口),使用Method即可. publ ...

  4. Java类的生命周期浅析

    类的生命周期?对象的生命周期?Spring bean 的生命周期?很多同学可能在学习java基础知识之初,很容易把这几个搞混.本文先来说说Java类的生命周期. 目录 知识前提 类的生命周期 加载(L ...

  5. JVM-类加载过程(Java类的生命周期)

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

  6. Java类的生命周期详解

    引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大多只是告 ...

  7. 【转】Java 类的生命周期详解

    一. 引 言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑,笔者打开百度搜了一下相关的问题,看到网上的资料很少有把这个问题讲明白的,主要是因为目前国内java方面的教材大 ...

  8. 【转载】详解java类的生命周期

    原文地址:http://blog.csdn.net/zhengzhb/article/details/7517213 引言 最近有位细心的朋友在阅读笔者的文章时,对java类的生命周期问题有一些疑惑, ...

  9. [Java]类的生命周期(上)类的加载和连接[转]

    本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 类加载器,顾名思义,类加载器(class loader)用来加载 Java 类到 Java ...

随机推荐

  1. kubeadm部署Kubernetes集群

    Preface 通过kubeadm管理工具部署Kubernetes集群,相对离线包的二进制部署集群方式而言,更为简单与便捷.以下为个人学习总结: 两者区别在于前者部署方式使得大部分集群组件(Kube- ...

  2. Java面试题系列(一)描述一下JVM加载class文件的原理机制

    JVM系列第4讲:从源代码到机器码,发生了什么? https://www.cnblogs.com/chanshuyi/p/jvm_serial_04_from_source_code_to_machi ...

  3. html5 canvas 弧形描边渐变

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. 【问题收集·知识储备】Xcode只能选择My Mac,不能选择模拟器如何解决?

      网友问题:请问打开一个应用,只能选择My Mac,不能选择模拟器如何解决? 答案:             下面将问答过程记录如下:     CHENYILONG Blog 请问打开一个应用,只能 ...

  5. Raid 磁盘阵列

    raid 原理与区别 raid0至少2块硬盘.吞吐量大,性能好,同时读写,但损坏一个就完蛋 raid1至少2块硬盘.相当镜像,一个存储,一个备份.安全性比较高.但是性能比0弱 raid5至少3块硬盘. ...

  6. vs-code 配置

    vs-code 快键键 命令面板 ctrl+shift+p vs-code 相关插件 AutoFileName Chinese (Simplified) Language Pack for Visua ...

  7. python格式化输出【转】

    今天写代码时,需要统一化输出格式进行,一时想不起具体细节,用了最笨的方法,现在讲常见的方法进行一个总结. 一.格式化输出 1.整数的输出 直接使用'%d'代替可输入十进制数字: >>> ...

  8. linux系统下安装nginx

    1.第一步:获取nginx的安装包 wget http://nginx.org/download/nginx-1.7.8.tar.gz 2.解压安装包tar -xvf nginx-1.7.8.tar. ...

  9. windows中连接hive-客户端

    参考连接:http://lxw1234.com/archives/2016/09/723.htm 这里主要介绍:Oracle SQL Developer 1. 下载,免安装包 SQL Develope ...

  10. C++资源之不完全导引

    1,前言 无数次听到“我要开始学习C++!”的呐喊,无数次听到“C++太复杂了,我真的学不会”的无奈.Stan Lippman先生曾在<C++ Primer>一书中指出“C++是最为难学的 ...