文档章节

Java的初始化块、静态初始化块、构造函数的执行顺序及用途探究

boluo1230
 boluo1230
发布于 2017/07/14 22:20
字数 836
阅读 49
收藏 0

Java与C++有一个不同之处在于,Java不但有构造函数,还有一个”初始化块“(Initialization Block)的概念。下面探究一下它的执行顺序与可能的用途。

执行顺序

  首先定义A, B, C三个类用作测试,其中B继承了A,C又继承了B,并分别给它们加上静态初始化块、非静态初始化块和构造函数,里面都是一句简单的输出。

  主类Main里面也如法炮制。

class A {
    static {
        System.out.println("Static init A.");
    }

    {
        System.out.println("Instance init A.");
    }

    A() {
        System.out.println("Constructor A.");
    }
}

class B extends A {
    static {
        System.out.println("Static init B.");
    }

    {
        System.out.println("Instance init B.");
    }

    B() {
        System.out.println("Constructor B.");
    }
}

class C extends B {

    static {
        System.out.println("Static init C.");
    }

    {
        System.out.println("Instance init C.");
    }

    C() {
        System.out.println("Constructor C.");
    }
}

public class Main {

    static {
        System.out.println("Static init Main.");
    }

    {
        System.out.println("Instance init Main.");
    }

    public Main() {
        System.out.println("Constructor Main.");
    }

    public static void main(String[] args) {
        C c = new C();
        //B b = new B();
    }
}

那么可以看到,当程序进入了main函数,并创建了一个类C的对象之后,输出是这样子的:

Static init Main.
Static init A.
Static init B.
Static init C.
Instance init A.
Constructor A.
Instance init B.
Constructor B.
Instance init C.
Constructor C.

 观察上面的输出,可以观察到两个有趣的现象:

  1. Main类是肯定没有被实例化过的,但是由于执行main入口函数用到了Main类,于是static初始化块也被执行了;
  2. 所有的静态初始化块都优先执行,其次才是非静态的初始化块和构造函数,它们的执行顺序是:
    1. 父类的静态初始化块
    2. 子类的静态初始化块
    3. 父类的初始化块
    4. 父类的构造函数
    5. 子类的初始化块
    6. 子类的构造函数

 

 那么如果有多个实例化对象,又会不会发生变化呢?于是在第一个C类的对象后面,再实例化一个B类的对象,再观察输出:

可以发现这输出跟前面的基本长得一样对吧?只是在后面多了4行,那是新的B类对象实例化时产生的信息,同样也是父类A的初始化块和构造函数先执行,再轮到子类B的初始化块和构造函数执行;同时还发现,静态初始化块的输出只出现了一次,也就是说每个类的静态初始化块都只在第一次实例化该类对象时执行一次。

 

总结: 

  1. 静态初始化块的优先级最高,也就是最先执行,并且仅在类第一次被加载时执行;
  2. 非静态初始化块和构造函数后执行,并且在每次生成对象时执行一次;
  3. 非静态初始化块的代码会在类构造函数之前执行。因此若要使用,应当养成把初始化块写在构造函数之前的习惯,便于调试;
  4. 静态初始化块既可以用于初始化静态成员变量,也可以执行初始化代码
  5. 非静态初始化块可以针对多个重载构造函数进行代码复用

 

此博客转载至博客园——BlackStorm,且未经许可不能用于商业目的。如有疑问或授权协商请与原作者联系。

 

本文转载自:http://www.cnblogs.com/BlackStorm/p/5699965.html

boluo1230
粉丝 0
博文 26
码字总数 9458
作品 0
哈尔滨
私信 提问
JAVA & .NET创建对象构造函数调用顺序

JAVA & .NET创建对象构造函数调用顺序 JAVA 定义Person类 定义Chinese类 创建Chinese类实例 输出结果如下: 执行顺序为: 基类静态初始化块——当前类静态初始化块——基类初始化块——基类构...

雪飞鸿
02/24
0
0
Java 面向对象编程之构造方法、构造代码块(1)

Java 面向对象编程之构造方法、构造代码块 面向对象编程是我们认识世界,创造事物的一种新的思维,其实就抓大放小,将所有共性的事物进行封装的过程。编程人员在进行流程作业时,可以方便的进...

hellation_
04/22
12
0
Java 语言中的实例初始化块 ( IIB) 详解

在 Java 语言中的类初始化块 文章中我们简单的介绍了下 Java 中的实例初始化块 ( IIB )。不过我觉得介绍的有点简单了,于是,再写一篇文章详细介绍下吧。 Java 语言中,存在三种操作:方法 ...

beves
2018/10/14
15
0
类装载步骤

类装载步骤 在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载、链接和初始化,其中链接又可以分成校验、准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的...

北极之北
2016/03/10
145
0
Java和Android ClassLoder对比以及Class加载过程

Java的ClassLoder的父子关系如下:Bootstrap--ExtClassClassLoader---AppClassLoader。 JVM启动时先运行启动类加载器Bottstrap,主要加载Java核心API;然后加载扩展类加载器ExtClassLoder,该...

JasmineBen
2018/05/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

程序设计基础(C)第06讲例程

1summing.c /* summing.c -- 根据用户键入的整数求和 */#include <stdio.h>int main(void){ long num; long sum = 0L; /* 把sum 初始化为0 */ int status; p......

树人大学数字媒体吴凡
14分钟前
4
0
聊聊nacos config的publishConfig

序 本文主要研究一下nacos config的publishConfig ConfigController nacos-1.1.3/config/src/main/java/com/alibaba/nacos/config/server/controller/ConfigController.java @Controller@R......

go4it
42分钟前
3
0
Eureka应用注册与集群数据同步源码解析

在之前的EurekaClient自动装配及启动流程解析一文中我们提到过,在构造DiscoveryClient类时,会把自身注册到服务端,本文就来分析一下这个注册流程 客户端发起注册 boolean register() t...

Java学习录
51分钟前
11
0
Java描述设计模式(15):责任链模式

本文源码:GitHub·点这里 || GitEE·点这里 一、生活场景描述 1、请假审批流程 公司常见的请假审批流程:请假天数 当 day<=3 天,项目经理审批当 3<day<=5 天,部门经理审批当 day>5 天...

知了一笑
今天
10
0
总结:数组与链表

1、内存申请:数组在内存上是连续的空间;链表,内存地址上可以是不连续的。 2、查询速度:数组可以随机访问,链表必须顺序访问,即从首个元素开始遍历,逐个查找,所以数组查询很快。 3、写入...

浮躁的码农
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部