Java中静态代码块、构造代码块、构造函数、普通代码块

版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons

一、格式区分及其性质

1.静态代码块

 Java使用static{//Code...}的格式代表静态代码块。位置:位于类内,与方法同层次

public class Test{
    static{
	//Code...
    }
}

 静态代码块会随着类的加载而执行,而且只执行一次,并且优先于各种代码块以及构造函数。一个类中若有多个静态代码块,则顺序执行它们。另一方面,静态的代码块也不能访问非静态域。  静态代码块的作用:一般情况下,如果有些代码需要在项目启动的时候就执行,这时候就需要静态代码块。比如一个项目启动需要加载的很多配置文件等资源,我们就可以都放入静态代码块中。

2.构造代码块

 Java使用{//Code...}的格式代表构造代码块,对比于静态代码块,其只少了static关键字的修饰。位置:位于类内,与方法同层次

public class Test {
    {
	//Code...
    }
}

 构造代码块在对象每次创建类的对象的时候都会被调用,显然可以用于对每个对象的独立初始化工作,比如对每个对象进行增序的编号。

3.构造函数

 Java使用与类同名的方法(有参或无参){//Code...}的格式代表构造函数。位置:位于类内,是一个作用特殊的方法

public class Test {
	public Test(){
	//Code...
    }
}

 构造函数和构造代码块的区别是,所有构造代码块在每个对象创建的时候都会执行,但是构造函数因为Java中的多态语法只会执行一个,并非是所有都进行执行。

4.普通代码块

 Java使用{//Code...}的格式代表构造代码块,对比于构造代码块,其区别是普通代码块跑到方法内部了。位置:位于方法内部。

public class Test {
	public void method(){
	//Code1...
	{
	//Code2...
	}
    }
}

 普通代码块的执行顺序和书写顺序一致(与方法体内部的代码比较执行顺序)。比如上述Code1先于Code2执行。


二、代码块的执行顺序

 为了说明四个代码块的执行顺序,我特意将其执行的顺序的逆序来编写代码(顺便将main方法纳入顺序比较):

Demo-1:

public class CodeBlock {
    static int i = 0;


    public CodeBlock() {
        System.out.printf("构造函数第%d个执行\n", ++i);
        {
            System.out.printf("普通代码块第%d个执行\n", ++i);
        }
    }

    {
        System.out.printf("构造代码块第%d个执行\n", ++i);
    }

    public static void main(String[] args) {
        System.out.println("执行main方法");
        CodeBlock codeBlock = new CodeBlock();

    }

    static {
        System.out.printf("静态代码块代码块第%d个执行\n", ++i);
    }

}

控制输出:

静态代码块代码块第1个执行
执行main方法
构造代码块第2个执行
构造函数第3个执行
普通代码块第4个执行

执行顺序:  静态代码块->构造代码块->构造函数->普通代码块 注意事项

  1. 普通代码块可以嵌入其余任何一个代码块中,且前三代码块内部代码都是顺序执行的;
  2. main方法晚于静态代码块执行,但是main内部的方法和其余三个代码块是顺序执行的;

三、涉及继承的代码块执行顺序

Demo-2:

public class CodeBolckExtends {
    public static void main(String[] args) {
        Son son = new Son();
    }
}


class  GrandPa{
    static int i =0;
    static {
        System.out.printf("父类的父类的静态代码块第%d个执行\n",++i);
        }

    public GrandPa() {
        System.out.printf("父类的父类的构造函数第%d个执行\n",++i);
    }
}

class Father extends GrandPa{
    static {
        System.out.printf("父类的静态代码块第%d个执行\n",++i);
    }
    public Father() {
        System.out.printf("父类的构造函数第%d个执行\n",++i);
    }
}



class Son extends Father{
    static {
        System.out.printf("子类的静态代码块第%d个执行\n",++i);
    }
    public Son() {
        System.out.printf("子类的构造函数第%d个执行\n",++i);
    }
}

控制台输出:

父类的父类的静态代码块第1个执行
父类的静态代码块第2个执行
子类的静态代码块第3个执行
父类的父类的构造函数第4个执行
父类的构造函数第5个执行
子类的构造函数第6个执行

 根据Demo-2代码实验可知,涉及继承的代码块执行顺序是这样的:  父类的静态方法->子类的静态方法->父类的构造代码块->父类的构造函数->子类的构造代码块->子类的构造函数 相关原理以及解释:

  1. 因为static修饰的代码在类加载的时候就进行执行,而类加载是先于对象创建的,所以子类和父类的静态方法要首先执行。又因为保护继承成立,我们无论是类加载,还是对象的创建,都是父类先行的,所以静态方法内部执行顺序是父类先于子类的。即:父类的静态方法->子类的静态方法。
  2. 对象的创建也因为如上继承的原因,父类对象先应当构造。注意:虽然有构造代码块先于构造函数执行的顺序这个原则,但是要保证父类对象成功安全地构造之后才应该构造子类对象,否则继承被破坏。所以有“父类的构造代码块->父类的构造函数->子类的构造代码块->子类的构造函数”如此的执行顺序。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券