java 初始化顺序以及由此可能引发的构造方法的潜在问题。

“设计构建器时一个特别有效的规则是:用尽可能简单的方法使对象进入就绪状态;如果可能,避免调用任何方法。在构建器内唯一能够安全调用的是在基础类中具有final属性的那些方法(也适用于private方法,它们自动具有final属性)。这些方法不能被覆盖,所以不会出现上述潜在的问题。”

摘录来自: (美)埃克尔 著 陈昊鹏 译. “java编程思想”。

那么潜在的问题是什么呢?再来看看代码:

abstract class Glypy {

    static int radius = 2;

    abstract void draw();

    Glypy() {
        System.out.println("Glyph() before draw()");
        draw();
        System.out.println("Glypy() after draw()");
    }
}

class RoundGlyph extends Glypy {
    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);
    }
}

输出结果:

Glyph() before draw()
RoundGlyph.draw(),radius=0
Glypy() after draw()
RoundGlyph.RoundGlyph,radius= 5

这不禁引出了一个初始化顺序的问题,对于继承的情况,显然是先初始化父类,然后子类。再加上先静态属性->静态块->非静态属性->构造方法,的顺序。

总结一下:先有类而后有对象,静态方法和静态块都属于类,所以先初始化静态属性和静态块。先有父类才有子类,所以先初始化父类。

                  有了类就可以初始化对象了,先初始化属性然后是构造方法,再加上先父类后子类。

  整个初始化可以分成两步,第一步:类初始化,父类的静态属性->父类静态块->子类静态属性->子类静态块

     第二步:对象初始化,父类属性->父类构造方法->子类属性->子类构造方法

来个例子:

    class Meal{
        Meal(){
            System.out.println("Meal");
        }
    }

    class Bread{
        Bread(){
            System.out.println("Bread");
        }
    }

    class Cheese{
        Cheese(){
            System.out.println("Cheese");
        }
    }

    class Lettuce{
        Lettuce(){
            System.out.println("Lettuce");
        }
    }

    class Lunch extends Meal{

        static   Cheese c = new Cheese();

        Lunch(){
            System.out.println("Lunch");
        }
    }

    class PortableLunch extends Lunch{

         Bread b = new Bread();


        PortableLunch(){
            System.out.println("PortableLunch");
        }
    }

    public class Sandwich extends PortableLunch{


        Lettuce l = new Lettuce();

        Sandwich(){
            System.out.println("Sandwich()");
        }

        public static void main(String[] args) {
            new Sandwich();
        }

    }

执行结果:

Cheese
Meal
Lunch
Bread
PortableLunch
Lettuce
Sandwich()



你可能感兴趣的:(java,继承,面向对象编程)