Java

Java编程思想 继承

2020-05-08  本文已影响0人  静享时光

这里不会介绍继承的基本概念和用法。这篇文章介绍继承中需要注意的几个点,并且文中也不会进行详细的理论说明,因为直接用示例,通过示例的结果进行总结分析,更清楚明了。

子类和父类的成员变量和构造方法的加载顺序

如果一个类继承了另一个类,在加载子类的构造方法时,会层次向上先加载父类的的构造。
另外需要注意的是,加载一个类的时候,类的成员变量会先于构造方法加载

class A {
    private String s;

    A(String s) {
        this.s = s;
        PrintUtils.print("Creating  A: " + s);
    }

    protected void dispose() {
        PrintUtils.print("disposing A: " + s);
    }
}

class B {
    private String s;

    B(String s) {
        this.s = s;
        PrintUtils.print("Creating  B: " + s);
    }

    protected void dispose() {
        PrintUtils.print("disposing B: " + s);
    }
}


class C {
    private A a = new A("C-A");
    private B b = new B("C-B");

    C() {
        PrintUtils.print("Creating  C");
    }

    protected void dispose() {
        PrintUtils.print("disposing C ");
        a.dispose();
        b.dispose();
    }
}

class D extends C {
    private A a = new A("D-A");
    private B b = new B("D-B");

    D() {
        PrintUtils.print("Creating  D");
    }

    protected void dispose() {
        PrintUtils.print("disposing D ");
        a.dispose();
        b.dispose();
        super.dispose();
    }
}

class E extends D {
    private A a = new A("E-A");
    private B b = new B("E-B");

    E() {
        PrintUtils.print("Creating  E" + "  a是否为空: " + (a == null) + " B是否为空: " + (b == null));
    }

    protected void dispose() {
        PrintUtils.print("disposing E ");
        a.dispose();
        b.dispose();
        super.dispose();
    }
}

public class PracticeDemo4 extends E {
    private A a = new A("PracticeDemo4-A");
    private B b = new B("PracticeDemo4-B");

    public PracticeDemo4() {
        PrintUtils.print("Creating  PracticeDemo4");
    }

    protected void dispose() {
        PrintUtils.print("disposing PracticeDemo4 ");
        a.dispose();
        b.dispose();
        super.dispose();
    }

    public static void main(String[] args) {
        PracticeDemo4 demo4 = new PracticeDemo4();
        PrintUtils.print("Bye!");
        demo4.dispose();
    }

    /**
     *
     *输出结果:
     Creating  A: C-A
     Creating  B: C-B
     Creating  C
     Creating  A: D-A
     Creating  B: D-B
     Creating  D
     Creating  A: E-A
     Creating  B: E-B
     Creating  E  a是否为空: false B是否为空: false
     Creating  A: PracticeDemo4-A
     Creating  B: PracticeDemo4-B
     Creating  PracticeDemo4
     Bye!
     disposing PracticeDemo4
     disposing A: PracticeDemo4-A
     disposing B: PracticeDemo4-B
     disposing E
     disposing A: E-A
     disposing B: E-B
     disposing D
     disposing A: D-A
     disposing B: D-B
     disposing C
     disposing A: C-A
     disposing B: C-B
     *
     */
总结:

由打印结果会发现,先层层向上初始化父类的成员变量,父类的成员变量加载结束之后,加载父类的构造函数,最后才加载子类的成员变量和构造方法。

构造器内部的多态行为

class Parent4 {
    public Parent4() {
        PrintUtils.print("Parent4 before");
        draw();
        PrintUtils.print("Parent4  after");
    }

    public void draw() {
        PrintUtils.print("Parent4 draw");
    }
}

class Child4 extends Parent4 {

    private int data;

    public Child4(int r) {
        data = r;
        PrintUtils.print("Child4  data: " + data);
    }

    public void draw() {
        PrintUtils.print("Child4 draw  data: " + data);
    }
}


public class PracticeTest5 {

    public static void main(String[] args) {
        new Child4(6);
        PrintUtils.print("//////////////////////////");
        new Child4(5);
        PrintUtils.print("//////////////////////////");
        new Child4(4);
        PrintUtils.print("//////////////////////////");
        new Child4(3);
        PrintUtils.print("//////////////////////////");
        new Child4(2);
        PrintUtils.print("//////////////////////////");
        new Child4(1);
        PrintUtils.print("//////////////////////////");


        /**
         * 打印结果
         *
         * Parent4 before
         * Child4 draw  data: 0
         * Parent4  after
         * Child4  data: 6
         * //////////////////////////
         * Parent4 before
         * Child4 draw  data: 0
         * Parent4  after
         * Child4  data: 5
         * //////////////////////////
         * Parent4 before
         * Child4 draw  data: 0
         * Parent4  after
         * Child4  data: 4
         * //////////////////////////
         * Parent4 before
         * Child4 draw  data: 0
         * Parent4  after
         * Child4  data: 3
         * //////////////////////////
         * Parent4 before
         * Child4 draw  data: 0
         * Parent4  after
         * Child4  data: 2
         * //////////////////////////
         * Parent4 before
         * Child4 draw  data: 0
         * Parent4  after
         * Child4  data: 1
         * //////////////////////////
         *
         *
         */
    }
}
总结:

由结果可以看到,在创建子类的时候,执行了父类的构造方法。在父类中触发调用draw方法,由于被覆写了,所以调用的是子类的draw方法,但是此时子类的成员变量data还没有初始化,所以还是默认的初始值0,而不是我们设置的值。直到子类的初始化完成,在子类的构造中打印的结果data才是我们设置的值。

上一篇 下一篇

猜你喜欢

热点阅读