• Java入门记(三):初始化顺序


    初始化顺序的规则

    1.在一个类的对象实例化时,成员变量首先初始化,然后才调用构造器,无论书写顺序。如果调用构造器前,没有显式初始化,那么会赋默认值。

    这样做法的原因可以理解为:构造器执行时可能会用到一些成员变量的初值。

    2.static变量早于所有其他的类成员变量初始化,同样无论书写顺序。但是static变量仅在所在类第一次被使用时初始化一次。

    3.基类构造器总是在导出类的构造过程中被调用,而且按照继承层级逐渐向上链接(调用顺序则是从基类开始向下)。可以理解为,这么做的逻辑关系是在一个类构建时可能会用到其父类的成员、方法。在清理时顺序相反。

    4.成员的初始化方法(包括基本数据类型的赋值)在基类构造器调用之后才会被调用。最初时,分配给对象的存储空间初始化二进制的零。

    例一出自《Java编程思想》第5.7.2节,为了便于演示初始化顺序,进行了缩减和重新编号。用构造器的参数标明执行顺序,演示1~2条规则:

    class Bowl {
        Bowl(int marker) {
            System.out.println("Bowl(" + marker + ")");
        }
    }
    
    class Cupboard {
        Bowl bowl1 = new Bowl(3);
        static Bowl bowl2 = new Bowl(1);
        int i;
        static int j = 5;
        Cupboard() {
            System.out.println("i:" + i);
            bowl4 = new Bowl(j);
            j = 6; 
        }
        Bowl bowl3 = new Bowl(4);
        static Bowl bowl4 = new Bowl(2);
    }
    
    public class ParaInitialization {
        public static void main(String args[]) {
            new Cupboard();
            new Cupboard();
        }
    }

    输出及对应注释:

    Bowl(1)      //第一个static变量
    Bowl(2)      //第二个static变量
    Bowl(3)      //第一个对象的第一个非static成员变量
    Bowl(4)             //第一个对象的第一个非static成员变量
    i:0         //未显示初始化的成员变量
    Bowl(5)      //更改static变量的值
    Bowl(3)     //第二个对象的第一个非static成员变量
    Bowl(4)     //第二个对象的第二个非static成员变量
    i:0
    Bowl(6)

      例二是一个演示第3条规则的简单示例。

    class A {
        A() {
            System.out.println("A");
        }
    }
    
    class B extends A {
        B() {
            System.out.println("B");
        }
    }
    
    class C extends B {
        C() {
            System.out.println("C");
        }
    }
    
    public class hrt {
        public static void main(String args[]) {
            new C();
        }
    }

    输出

    A
    B
    C

    例三用于演示规则4。调用父类构造器时,构造器中的方法被子类方法覆盖。

    class Glyph {
        void draw() {
            System.out.println("Glyph.draw(");
        }
    
        Glyph() {
            System.out.println("Glyph() before draw()");
            draw();
            System.out.println("Glyph() after draw()");
        }
    }
    
    class RoundGlyph extends Glyph {
        int radius = 1;
        RoundGlyph(int r) {
            radius = r;
            System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
        }
    
        void draw() {
            System.out.println("RoundGlyph.draw(), radius = " + radius);
        }
    }
    
    public class PolyConstructors {
        public static void main(String[] args) {
            new RoundGlyph(5);
        }
    }

    这么多条规则,记起来实在让人头大。将它们按顺序编排会易读很多。

    对象初始化顺序,如果有对应成员/父类的才执行对应条目:

    1.将分配给对象的存储空间初始化为二进制的零;

    2.调用基类构造器,从最顶层/根的基类开始;

    3.按照声明的顺序,使用直接的赋值或者初始化方法,先依次初始化static变量,再依次初始化非static变量;

    4.调用本对象所属类的构造器。 

  • 相关阅读:
    Spring Boot教程(十三)整合elk(2)
    Spring Boot教程(十二)整合elk(1)
    Spring Boot教程(十一) springboot程序构建一个docker镜像
    Spring Boot教程(十)异步方法测试
    Spring Boot教程(九)异步方法
    Spring Boot教程(八)创建含有多module的springboot工程
    Spring Boot教程(七)通过springboot 去创建和提交一个表单
    Spring Boot教程(六)在springboot中验证表单信息
    Spring Boot教程(五)调度任务
    原码, 反码, 补码 详解(转)
  • 原文地址:https://www.cnblogs.com/wuyuegb2312/p/init-sequence.html
Copyright © 2020-2023  润新知