[Java] 类的初始化步骤
前言
类的初始化过程,可在多线程环境下进行的,为了简化,本文介绍的单线程情况下的类初始化步骤。
此外,继承情况下的顺序不是本文焦点,本文重点在于一个类的内部字段的初始化顺序。想了解继承情况下的初始化情况,可参看 类和接口的初始化步骤 - 继承方面
本文介绍的是类的初始化,不涉及实例的初始化。
正文
类的初始化,包括静态代码块的初始化、静态字段(类的字段)的初始化。
类的初始化触发条件:
1) T 是一个类,且 T 的一个实例被创建。
2) T 的一个静态方法被调用
3) T 的一个静态字段被赋值
4) T 的一个静态字段被使用,并且该字段不是一个字面常量。
5) T 是一级类,并且内嵌的断言语句被执行
本文的采用第 4) 种触发条件进行演示。
一个类的初始化步骤:
1. 在一个类被初始化之前,也就是在任何非字面类常量的类字段被初始化之前,字面类常量先完成初始化,如字段 static final Stirng a = "good"。
2. 当类被触发进行初始化,若其直接父类还没有被初始化,先对直接父类进行初始化;若直接父类的直接父类没有被初始化,则先对直接父类的直接父类进行初始化,以此类推,直到 Object 类或某一级别的祖父类已被初始化。
3. 初始化所有非类常量的类字段,同时初始化静态代码块,按文本序。
例子
Super, 父类,被初始化有输出
Test,测试主体类,继承 Super, 拥有四个字段:字面类常量 field1, 非字面的类常量 field2, 类变量 field3, 实例变量 field4; 拥有静态代码块,在类被初始化时被执行。
Test$InnerClass,Test 的内部类,在 Test 初始化时候被调用,用于表明字面类常量、非字面类常量两者被初始化的时间是不一样的。
InitDemo, 演示类的时候步骤。
具体代码
Super, 父类
public class Super {
    static {
        System.out.println("initializing Super ");
    }
}
Test, 测试的主体类
public class Test extends Super {
    public static final String field1 = "Test.field1";
    public static final String field2 = InnerClass.pint("Initializing Test.field2 ");
    public static String field3 = InnerClass.pint("Initializing Test.field3 ");
    public String field4 = InnerClass.pint("Initializing Test.field4 ");
    static{
        System.out.println("initializing Test class ");
        System.out.println("\t" + field1 + " - " + field2 + " - " + field3);
    }
    public Test(){
        System.out.println("in Test() ");
    }
    public void bMethod() {
        System.out.println("in Test.bMethod() ");
    }
    public static class InnerClass{
        public static String pint(String s){
            System.out.println(s);
            return s.substring(s.indexOf(" ") + 1);
        }
        static {
            System.out.println("initialzation in Test$innerClass ");
            System.out.println("\t" + field1 + " - " + field2 + " - " + field3);
        }
    }
}
InitDemo, 演示 Test 被初始化的步骤
public class InitDemo {
    public static void mian(){
        System.out.println(Test.field1);
        System.out.println("----------");
        System.out.println(Test.field2);
    }
}
输出如下
Test.field1
----------
initializing Super
initialzation in Test$innerClass
Test.field1 - null - null
Initializing Test.field2
Initializing Test.field3
initializing Test class
Test.field1 - Test.field2 - Test.field3
Test.field2
从输出可以看出 :
在输出字面类常量 Test.field1 时候, Test 类并没有被初始化。而在输出非字面的类常量 Test.field2 时候,触发了 Test 的初始化。
在 Test 类被初始化之前,其父类 Super 先被初始化。
第 5 行是内部类 Test$innerClass 的输出,Test 类被初始化之前,非字面类字段 filed2、field3 都为 null,只有字面类常量 field1 已被赋值。
地 9 行是 Test 类静态代码块的初始化运行,此时类字段 field2、field3 均已被初始化。
类的初始化只是对类字段 ( field1、field2、field3 ) 进行初始化赋值,实例字段 field4 并不会被初始化赋值,需要等到创建实例是才会被初始化创建。
参考资料
12.4. Initialization of Classes and Interfaces, The Java Language Specification, Java SE 8 Edition
What is the best way to implement constants in Java?, stackOverflow
[Java] 类的初始化步骤的更多相关文章
- java类的初始化和构造函数
		本人小白一枚,看java类的初始化的时候好晕的说,我觉着书上尽管说的对.但总认为有些信息没说出来,没说清楚,看了好多文章博客的,如今有些感悟,来小写下总结,也算是为以后再次复习种个好果子. 先摘一下书 ... 
- 图示Java类的初始化顺序
		Java类的初始化顺序 在开发中,知道Java类的初始化顺序才能让我们更加清楚地掌握程序的执行流程.先把结论贴出来,Java里,从图里的1~6,分别按顺序执行. 以下为代码验证阶段,一共三个类 ... 
- java类的初始化
		转载:http://blog.csdn.net/moreevan/article/details/6968718 我们知道一个类(class)要被使用必须经过装载,连接,初始化这样的过程.下面先对这三 ... 
- java类的初始化顺序
		在java中,当我们new一个对象时,对象中的成员,初始化块以及构造方法的加载是有一定的顺序的,看下面一副图: 一.单类(无基类)下的初始化顺序: public class Parent { stat ... 
- java类的初始化和对象的创建顺序
		学习java编程思想--类的初始化p146 类的加载顺序* 1加载器启动找到 xxx.class文件,通过extends关键字寻找基类,先加载基类* 2类初始化先初始化static成员变量和stati ... 
- 分析java类的初始化契机
		分析java类的静态成员变量初始化先于非静态成员变量 依上图中当class字节码文件被jvm虚拟机加载到内存中依次经过 连接 验证:对字节码进行验证 准备:给静态变量分配内存并赋予变量类型各自的默 ... 
- Java类的初始化与实例对象的初始化
		Java对象初始化详解 2013/04/10 · 开发 · 1 评论· java 分享到:43 与<YII框架>不得不说的故事—扩展篇 sass进阶篇 Spring事务管理 Android ... 
- java类的初始化块/执行顺序,实例化对象数据赋值
		java里初始化一个类的对象,通过初始化快或者构造方法进行数据赋值.与其相关的执行代码有这么几种: 静态初始化块 初始化块 构造方法 静态初始化块 静态初始化块只在类加载时执行一次,同时静态初始化块只 ... 
- Java类的初始化过程及清理
		一.类的数据成员初始化 Java中类的数据成员初试化可能有两种形式. 在定义类成员变量的地方直接提供初始化值(这是C++中不允许的) 在构造器中初试化.(Java中不存在类似C++中的初始化列表) 两 ... 
随机推荐
- Hibernate分页
			1. HQL分页: Session session = HibernateUtil.getInstance().getSession(); Query query = session.createQu ... 
- codevs 1036 商务旅行 (倍增LCA)
			/* 在我还不知道LCA之前 暴力跑的SPFA 70分 三个点TLE */ #include<iostream> #include<cstdio> #include<cs ... 
- git 的记住用户名和密码和一些常用
			git config --global core.autocrlf falsegit config --global color.ui truegit config --global credenti ... 
- (转)DEDECMS模板原理、模板标签学习 - .Little Hann
			本文,小瀚想和大家一起来学习一下DEDECMS中目前所使用的模板技术的原理: 什么是编译式模板.解释式模板,它们的区别是什么? 模板标签有哪些种类,它们的区别是什么,都应用在哪些场景? 学习模板的机制 ... 
- c - static 变量
			static变量和普通的局部变量不同,位于数据区中,在函数的外部初始化. ref: http://www.cnblogs.com/hustcat/archive/2009/06/30/1513755. ... 
- RAC检查各资源
- jdbc中的Statement对象和Preparedstatement对象的区别,以及通过jdbc操作调用存储过程
			一. java.sql.* 和 javax.sql.*的包的类结构 |- Driver接口: 表示java驱动程序接口.所有的具体的数据库厂商要来实现此接口. |- connect(url, p ... 
- linux关机重启命令浅析
			linux关机重启命令 今天我们来介绍下linux系统中常用到的关机重启命令—shutdown.halt.reboot.poweroff以及init. shutdown命令 以安全的方式关闭系统或重启 ... 
- Activiti 工作流得到最后一次批注的时间
			我们有时候在工作流开发中可能会遇到这样的需求,就是已经审批结束的流程,可能我们还是仍然需要修改业务表的结果,而且我们需要一个时间期限,比如:在5天内可以进行修改 ,这个时候我们就需要得到我们最后一步审 ... 
- 初涉JavaScript模式 (8) : 函数 【概述】
			什么是函数 函数,是一个大型程序中的某部份代码,由一个或多个语句块组成.它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性.(维基百科) 函数的特点 第一类对象 在JavaScript世界中 ... 
