天天看點

基于Java代碼對this,動态綁定,覆寫和隐藏的探讨和思考

先放一段代碼,通過修改參數來了解以下四個問題:

1.父類子類混合建立一個新對象的構造邏輯(多态性及動态綁定)

2.this.方法實質

3.靜态方法的隐藏(成員變量)

4.非靜态方法的覆寫

對1的解釋:聲明父類建立子類對象的與正常建立對象的差別(A p = new B()):

先看如下代碼,A是B的父類,m()被覆寫。

class A {
    int x=;//被隐藏
    A() {
        System.out.println("這裡建構了一個父類對象");
    }

    void m() {//被覆寫
        System.out.println("這裡是父類的執行個體方法m()");
    }

    void m1() {
        this.m();
        this.m2();
        this.m3();
        System.out.println(this.x);
        System.out.println("這裡是父類的執行個體方法m1()");
    }

    static void m2(){//被隐藏
    System.out.println("這裡是父類的靜态方法m2()");
}

    void m3() {//未被覆寫
        System.out.println("這裡是父類的執行個體方法m3()");
    }   
}

class B extends A {
    int x=;
    B() {
        System.out.println("這裡建構了一個子類對象");
    }

    void m() {
        System.out.println("這裡是子類的執行個體方法m()");
    }

    static void m2(){
    System.out.println("這裡是父類的靜态方法m2()");
}

}

public class Test1 {
    public static void main(String[] args) {
        A a = new A();
        a.m1();
        System.out.println();
        B b = new B();
        b.m1();
        System.out.println();
        A c = new B();
        c.m1();
    }
}
           

輸出結果為:

這裡建構了一個父類對象

這裡是父類的執行個體方法m()

這裡是父類的靜态方法m2()

這裡是父類的執行個體方法m3()

1

這裡是父類的執行個體方法m1()

這裡建構了一個父類對象

這裡建構了一個子類對象

這裡是子類的執行個體方法m()

這裡是父類的靜态方法m2()

這裡是父類的執行個體方法m3()

1

這裡是父類的執行個體方法m1()

這裡建構了一個父類對象

這裡建構了一個子類對象

這裡是子類的執行個體方法m()

這裡是父類的靜态方法m2()

這裡是父類的執行個體方法m3()

1

這裡是父類的執行個體方法m1()

可以看出:

構造順序為

父類屬性初始化-》父類構造方法-》子類屬性初始化-》子類構造方法

而且實際會構造的對象要看聲明的類型,如果是子類就是子類的。

其中

A c = new B();

建構順序為先建構父類,再建構子類。但隻能調用被子類覆寫的方法,而不能調用子類獨用的方法。(在B中設計一個父類沒有的m3方法,然後用c.m3()調用,發現報錯,m3()未被定義。哪怕m3()改為靜态方法也不行)

也就是說隻多了一個被覆寫的方法,其他沒影響。

而且this指的就是this這個詞自己所在的類,而非網上部分文章說的是建立的對象(new後面的)的類,隻是被覆寫的方法除外,隐藏了沒用。而且A中的this去掉也沒有影響。

父類中被覆寫的方法在父類中無法調用,在子類中可以用super調用,其他地方可以通過隻建立父類對象直接調用,用子類間接調用隻能找子類裡用的super方法的。

被隐藏的變量和靜态方法可以在父類中被直接調用,其他和覆寫一緻。

下面可以利用另一端代碼進行練習測試:

class A{
    int x = ;//被隐藏
    void print(){//被覆寫
        System.out.println("這裡是父類方法,x="+x);//父類A的方法中通路的變量必然是A類或A的父類的,不可能通路B類的。
        m();//父類A的方法中調用的執行個體方法m()是子類B的,由于發生了覆寫
    }
    void m(){//被覆寫
        System.out.println("這裡是父類的執行個體方法m()");
    }
    static void m2(){//被隐藏
        System.out.println("這裡是父類的靜态方法m2()");
    }
}
class B extends A{
    int x = ; 
    void print(){
        System.out.println("這裡是子類方法,x="+x);//子類方法通路的變量是子類對象的(當然條件是子類中聲明了這個變量)
        System.out.println("這裡是子類方法,super.x="+super.x);//super.x是父類對象的
        super.print();//調用父類的print()方法
        m();//調用本對象的m()方法
    }
    void m(){
        System.out.println("這裡是子類的執行個體方法m()");
    }
    static void m2(){
        System.out.println("這裡是子類的靜态方法m2()");
    }
    static void m3(){//靜态與否都沒用
        System.out.println("這裡是子類的執行個體方法m3()");
    }
}
public class Test{
    public static void main(String []s){
        A p = new B();
        System.out.println(p.x);//通過引用變量p來通路變量或靜态方法,要看p的聲明類型。是以x是A類的。
        p.m2();//同上。靜态方法m2()是A類的。
        p.print();//通過引用變量p來通路執行個體方法,要看p指向的對象的實際類型。由于覆寫,調用的print()方法是子類的。
        p.m3();//報錯The method m3() is undefined for the type A
    }
}