Java虚拟机JVM学习04 类的初始化

类的初始化

  在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值。

  在程序中,静态变量的初始化有两种途径:

  1.在静态变量的声明处进行初始化;

  2.在静态代码块中进行初始化。

  没有经过显式初始化的静态变量将原有的值。

  一个比较奇怪的例子:

package com.mengdd.classloader;

class Singleton {

    // private static Singleton mInstance = new Singleton();// 位置1
// 位置1输出:
// counter1: 1
// counter2: 0
public static int counter1;
public static int counter2 = 0; private static Singleton mInstance = new Singleton();// 位置2 // 位置2输出:
// counter1: 1
// counter2: 1 private Singleton() {
counter1++;
counter2++;
} public static Singleton getInstantce() {
return mInstance;
}
} public class Test1 { public static void main(String[] args) { Singleton singleton = Singleton.getInstantce();
System.out.println("counter1: " + Singleton.counter1);
System.out.println("counter2: " + Singleton.counter2);
}
}

  可见将生成对象的语句放在两个位置,输出是不一样的(相应位置的输出已在程序注释中标明)。

  这是因为初始化语句是按照顺序来执行的。

  静态变量的声明语句,以及静态代码块都被看做类的初始化语句,Java虚拟机会按照初始化语句在类文件中的先后顺序来依次执行它们。

类的初始化步骤

  1.假如这个类还没有被加载和连接,那就先进行加载和连接

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

  3.假如类中存在初始化语句,那就依次执行这些初始化语句。

类的初始化时机

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

  1.主动使用

  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类的方式都被看作是对类的被动使用,都不会导致类的初始化

接口的特殊性

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

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

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

  因此,一个父接口并不会因为它的子接口或者实现类的初始化而初始化,只有当程序首次使用特定接口的静态变量时,才会导致该接口的初始化。

final类型的静态变量

  final类型的静态变量是编译时常量还是变量,会影响初始化语句块的执行。

  如果一个静态变量的值是一个编译时的常量就不会对类型进行初始化(类的static块不执行);

  如果一个静态变量的值是一个非编译时的常量,即只有运行时会有确定的初始化值,则就会对这个类型进行初始化(类的static块执行)。

  例子代码:

package com.mengdd.classloader;

import java.util.Random;

class FinalTest1 {
public static final int x = 6 / 3; // 编译时期已经可知其值为2,是常量
// 类型不需要进行初始化
static {
System.out.println("static block in FinalTest1");
// 此段语句不会被执行,即无输出
}
} class FinalTest2 {
public static final int x = new Random().nextInt(100);// 只有运行时才能得到值
static {
System.out.println("static block in FinalTest2");
// 会进行类的初始化,即静态语句块会执行,有输出
}
} public class InitTest { public static void main(String[] args) {
System.out.println("FinalTest1: " + FinalTest1.x);
System.out.println("FinalTest2: " + FinalTest2.x);
}
}

主动使用的归属明确性

  只有当程序访问的静态变量或静态方法确实在当前类或当前接口中定义时,才可以认为是对类或接口的主动使用。

package com.mengdd.classloader;

class Parent {
static int a = 3; static {
System.out.println("Parent static block");
} static void doSomething() {
System.out.println("do something");
}
} class Child extends Parent {
static {
System.out.println("Child static block");
}
} public class ParentTest { public static void main(String[] args) { System.out.println("Child.a: " + Child.a);
Child.doSomething(); // Child类的静态代码块没有执行,说明Child类没有初始化
// 这是因为主动使用的变量和方法都是定义在Parent类中的
}
}

ClassLoader类

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

package com.mengdd.classloader;

class CL {

    static {
System.out.println("static block in CL");
}
} public class ClassLoaderInitTest { public static void main(String[] args) throws Exception {
ClassLoader loader = ClassLoader.getSystemClassLoader();
Class<?> clazz = loader.loadClass("com.mengdd.classloader.CL");
// loadClass方法加载一个类,并不是对类的主动使用,不会导致类的初始化 System.out.println("----------------");
clazz = Class.forName("com.mengdd.classloader.CL");
} }

参考资料

  圣思园张龙老师Java SE系列视频教程。

Java虚拟机JVM学习04 类的初始化的更多相关文章

  1. Java虚拟机JVM学习07 类的卸载机制

    Java虚拟机JVM学习07 类的卸载机制 类的生命周期 当Sample类被加载.连接和初始化后,它的生命周期就开始了. 当代表Sample类的Class对象不再被引用,即不可触及时,Class对象就 ...

  2. Java虚拟机JVM学习02 类的加载概述

    Java虚拟机JVM学习02 类的加载概述 类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对 ...

  3. Java虚拟机JVM学习01 流程概述

    Java虚拟机JVM学习01 流程概述 Java虚拟机与程序的生命周期 一个运行时的Java虚拟机(JVM)负责运行一个Java程序. 当启动一个Java程序时,一个虚拟机实例诞生:当程序关闭退出,这 ...

  4. Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论

    Java虚拟机JVM学习06 自定义类加载器 父委托机制和命名空间的再讨论 创建用户自定义的类加载器 要创建用户自定义的类加载器,只需要扩展java.lang.ClassLoader类,然后覆盖它的f ...

  5. Java虚拟机JVM学习05 类加载器的父委托机制

    Java虚拟机JVM学习05 类加载器的父委托机制 类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap ...

  6. Java虚拟机JVM学习03 连接过程:验证、准备、解析

    Java虚拟机JVM学习03 连接过程:验证.准备.解析 类被加载后,就进入连接阶段. 连接就是将已经读入到内存的类的二进制数据合并到虚拟机的运行时环境中去. 连接阶段三个步骤:验证.准备和解析. 类 ...

  7. Java虚拟机(JVM) - 学习总结(全)

    深入理解java虚拟机---学习总结: 1.Java内存区域 1.1 java运行时数据区 Java 虚拟机所管理的内存如下图所示,基于JDK1.6. 基于jdk1.8画的JVM的内存模型 (1) 程 ...

  8. java虚拟机JVM学习笔记-基础知识

    最近使用开发的过程中出现了一个小问题,顺便记录一下原因和方法--java虚拟机 媒介:JVM是每一位从事Java开发工程师必须翻越的一座大山! JVM(Java Virtual Machine)JRE ...

  9. JVM学习04:类的文件结构

    JVM学习04:类的文件结构 写在前面:本系列分享主要参考资料是  周志明老师的<深入理解Java虚拟机>第二版. 类的文件结构知识要点Xmind梳理

随机推荐

  1. Activity的四种launchMode《转》

    转自:http://blog.csdn.net/liuhe688/article/details/6754323/ Activity的四种launchMode. launchMode在多个Activi ...

  2. 谈谈Android 6.0运行时权限理解

    前言 谷歌在2015年8月份时候,发布了Android 6.0版本,代号叫做“棉花糖”(Marshmallow ),其中的很大的一部分变化,是在用户权限授权上,或许是感觉之前默认授权的不合理,现在6. ...

  3. jQuery 简介和安装

    什么是jQuery jQuery是一个轻量级的"写的少,做的多"的JavaScript库. jQuery库包含以下功能: HTML 元素选取 HTML 元素操作 CSS 操作 HT ...

  4. 基于HTML5的Web SCADA工控移动应用

    在电力.油田燃气.供水管网等工业自动化领域Web SCADA的概念已经提出了多年,早先年的Web SCADA前端技术大部分还是基于Flex.Silverlight甚至Applet这样的重客户端方案,在 ...

  5. Ajax学习记录

    Ajax 1:ajax是一种页面局部刷新的技术,不是整个页面刷新.这里就像论坛评论里面的刷新,只是局部的,不是页面全部提交到服务器. 2:页面不刷新,创建个WebClient,它和服务器进行交互.&l ...

  6. 开源的即时通讯框架 (endv.cn) (一)

    先实现几个常用基本功能, 1.富文本编辑器.文字的发送与接收 2.表情选择.插入.发送.读取 3.截图的插入.发送.接收 4.视频的获取.发送.接收 5.内存垃圾回收 客户端模拟服务端发送与接收 源码 ...

  7. Emit学习(3) - OpCodes - 循环和异常

    本来准备直接进入Dapper的, 但是昨天初步看了一下, 内容不少, Dapper不愧是一款成熟的框架, 里面对各种情况的考虑, 很实用, 不过这也使得我短时间内看不完, 所以得等几天了. 那就先来看 ...

  8. Razor语法

    1. 截取字符串  @(i.Title.Length > 18 ? i.Title.Substring(0, 18) + "" : i.Title) 2. 格式化日期  @s ...

  9. C#的变迁史 - C# 5.0 之其他增强篇

    1. 内置zip压缩与解压 Zip是最为常用的文件压缩格式之一,也被几乎所有操作系统支持.在之前,使用程序去进行zip压缩和解压要靠第三方组件去支持,这一点在.NET4.5中已有所改观,Zip压缩和解 ...

  10. virtualbox创建com对象失败(解决方法)

      我的电脑是win7 64bit的,和舍友同时安装virtualbox,她的是win8,安装得很顺利. 我的就比较坎坷了,安装完打开后就出现了这个问题.   试过网上的好几个方法都不行,最后结合了两 ...