代码块又称为初始化块,属于类中的成员【即是类的一部分】,类似于方法,将逻辑语句封装在方法中,通过{}包围起来。但和方法名不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显示调佣,而是加载类时,或创建对象时隐式调用。 基本语法 [修饰符]{ 代码 } 1、修饰符 可选,要写的话,只能写static。 2、代码块分为俩类,使用static修饰的叫做静态代码块,没有static修饰的,叫做普通代码块。 3、逻辑语句可以为任何逻辑语句(输入,输出,方法调用,循环,判断等)。 4、; 号可以写上,也可以省略。 1、static代码块也叫静态代码块,作用就是对类进行初始化,而却它随着 类的加载 而执行,并且只会 执行一次。如果是普通代码块,每创建一个对象,就执行。 2、类什么时候被加载【重要背!!】 创建对象实例时(new)。 创建子类对象实例,父类也会被加载。 使用类的静态成员的时(静态属性,静态方法)。 3、普通的代码块,在创建对象实例时,会被隐式的调用。 被创建一次就会被调用一次。 如果只是使用类的静态成员时,普通代码块并不会执行。


public class CodeBlockDetail01 {
    public static void main(String[] args) {
        A a = new A();
        A a2 = new A();
        A.num();

    }
}
class A{
    private static int i =10;

    static {
        System.out.println("我是static代码块....");
    };

    {
        System.out.println("我是普通代码块.....");
    };

    public static void num(){
        System.out.println(i);
    }
}

 输出结果:

我是static代码块....
我是普通代码块.....
我是普通代码块.....
10


创建一个对象时,在一个类 调用顺序是: 1、调用惊天代码块和静态属性初始化 注意:静态代码块和静态属性初始化的优先级一样,如果有多个 静态变量初始化,则按他们定义的顺序调用。 2、调用普通代码块和普通属性的初始化 注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个 普通代码块和多个普通属性初始化,则按定义调用。 3、调用构造方法。


例子:

public class CodeBlockDetail02 {
    public static void main(String[] args) {

        AA aa = new AA();//get被调用   静态代码块   num被调用  普通代码块   构造器

    }
}

class AA{

    //无参构造器
    public AA(){
        System.out.println("构造器");
    }

    private static int a = AA.get();

    private  int b = AA.num();

    {
        System.out.println("普通代码块");
    }

    static {
        System.out.println("静态代码块...");
    }


    public static int get(){
        System.out.println("get被调用");
        return 100;
    }

    public static int num(){
        System.out.println("num被调用");
        return 20;
    }
}

可以看到输出的顺序是:

get被调用
静态代码块...
num被调用
普通代码块
构造器


构造器的最前面其实隐含了 super() 和 调用普通代码块,静态相关的代码块和属性初始化, 在类加载时就执行完毕,因此是优先于 构造器和普通代码块 执行的。以下例子可以看出:


public class CodeBlockDetail03 {
    public static void main(String[] args) {
        BB bb = new BB();
    }
}

class AAA{

    {
        System.out.println("AAA的代码块");
    }
    public AAA(){
        //隐藏的第一个:super();
        //第二个:调用本类的普通代码块
        System.out.println("AAA构造器");
    }
}


class BB extends AAA{

    {
        System.out.println("BBB的普通代码块");
    }
    public BB(){
        //隐藏的第一个:super();
        //第二个:调用本类的普通代码块
        System.out.println("BB构造器");
    }
}

输出的结果: 

AAA的代码块
AAA构造器
BBB的普通代码块
BB构造器


我们来看一下创建一个子类时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化, 构造方法的调用顺序如下: 1、父类的静态代码块和静态属性(优先级一样,按定义顺序执行) 2、子类的静态代码块和静态属性(优先级一样,按定义顺序执行) 3、父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行) 4、父类的构造方法 5、子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行) 6、子类的构造方法 //面试题 静态代码块只能直接调用静态成员,普通代码可以调用任意成员。


以下是例子和结果,大家可以理解一下

public class CodeBlockDetail04 {
    public static void main(String[] args) {

        F f = new F();
    }
}

class D{
    private static int a = D.sum();

    static{
        System.out.println("父类的静态代码块");
    }

    {
        System.out.println("父类的普通代码块");
    }

    private int  aa = sum1();

    public static int sum(){
        System.out.println("static 父类的sum方法被调用");
        return 100;
    }

    public int sum1(){
        System.out.println("父类的sum1 方法被调用");
        return 100;
    }

    public D(){
        System.out.println("父类的构造器");
    }

}

class E extends D{

    private int s = eee();

    public int eee(){
        System.out.println("eee 方法");
        return 100;
    }

    private static int D = E.ee();

    {
        System.out.println("E的普通代码块");
    }

    public static int ee(){
        System.out.println("static 子类E的DD方法被调用");
        return 100;
    }

    static{
        System.out.println("E的静态代码块");
    }

    public E(){
        //super();
        //代码块
        System.out.println("E的构造器");
    }

}

class F extends E{
    static{
        System.out.println("子类F的静态代码块");
    }
    {
        System.out.println("子类F的普通代码块");
    }

    public F(){
        System.out.println("F的构造器");
    }
}

输出:

static 父类的sum方法被调用
父类的静态代码块
static 子类E的DD方法被调用
E的静态代码块
子类F的静态代码块
父类的普通代码块
父类的sum1 方法被调用
父类的构造器
eee 方法
E的普通代码块
E的构造器
子类F的普通代码块
F的构造器

进程已结束,退出代码0