上接深入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. mybatis入门基础----高级映射(一对一,一对多,多对多)

    阅读目录 一:订单商品数据模型 二.一对一查询 三.一对多查询 四.多对多查询 回到顶部 一:订单商品数据模型 1.数据库执行脚本 创建数据库表代码: CREATE TABLE items ( id ...

  2. dp的进阶 (一)

    熟练掌握dp的定义方法. ①四维dp的转移,生命值转移时候需要注意的 ②集合的定义,判断二进制内部是否有环 ③很难想到的背包问题 ④博弈类型的dp ⑤排列组合类型dp ⑥01背包的变种(01背包+完全 ...

  3. unp学习笔记——Chapter1

    1.发现网络拓扑的几个重要的命令 (1).netstat -i 提供网络接口的信息.我们还指定-n 标志以输出数值地址,而不是试图把它们反向解析成名字.netstat -r 展示路由表. dzhwen ...

  4. Flex 自定义 Zlert 组件!

    说明: 原生的 Alert.show 参数,要显示的按钮你只能 Alert.OK | Alert.Cancel 这样; 自定义 Zlert 参数跟原生的 差不多,按钮写法是这样写的: {"b ...

  5. HTML5 移动开发(CSS3设计移动页面样式)

    1.如何创建CSS样式表 2.CSS3的卓越特性 3.基于设备属性改变样式的媒体查询 4.如何使用属性改变元标签创建更美观移动页面   层叠样式表是移动WEB开发中的一个重要组成部分,本次分享将学到如 ...

  6. swift中Any,AnyObject,AnyClass的区别

    这几个概念让人很迷惑,看了很多帖子,终于搞明白了,简单总结: Any 和 AnyObject 是 Swift 中两个妥协的产物.什么意思呢,oc中有个id关键字,表示任何对象,oc和swift混编的时 ...

  7. Raid 磁盘阵列

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

  8. P4549 【模板】裴蜀定理

    题目描述 给出n个数(A1...An)现求一组整数序列(X1...Xn)使得S=A1X1+...AnXn>0,且S的值最小 输入输出格式 输入格式: 第一行给出数字N,代表有N个数 下面一行给出 ...

  9. 对git简单的认识

    了解git工作区.暂存区.版本库: 其中,使用 git add .就是将文件添加到了暂存区:而git commit -m ‘desc’:将暂存区的文件添加到版本库: 每次更新项目的步骤: 1)每次更新 ...

  10. __class__属性与元类

    class M(type): def __str__(self): return "gege" aa = "ccf" cc = "ccc" ...