理解多態AND理解父類引用指向子類對象

假設如今有一個父類Father,它裏面的變量須要佔用1M內存.有一個它的子類Son,它裏面的變量須要佔用0.5M內存. ide

如今經過代碼來看看內存的分配狀況: 函數

Father f = new Father();//系統將分配1M內存. 測試

Son s = new Son();//系統將分配1.5M內存. this


由於子類中有一個隱藏的引用super會指向父類實例,因此在實例化子類以前會先實例化一個父類,也就是說會先執行父類的構造函數. 對象

因爲s中包含了父類的實例,因此s能夠調用父類的方法. 繼承


Son s1 = s;//s1指向那1.5M的內存.(能夠理解爲就是:子類引用指向子類對象) 內存


Father f1 = (Father)s;//這時f1會指向那1.5M內存中的1M內存,便是說,f1只是指向了s中實例的父類實例對象,因此f1只能調用父類的方法(存儲在1M內存中),而不能調用子類的方法(存儲在0.5M內存中). 虛擬機


Son s2 = (Son)f;//這句代碼運行時會報ClassCastException.由於f中只有1M內存,而子類的引用都必需要有1.5M的內存,因此沒法轉換. io


Son s3 = (Son)f1;//這句能夠經過運行,這時s3指向那1.5M的內存.因爲f1是由s轉換過來的,因此它是有1.5M的內存的,只是它指向的只有1M內存. 編譯

 


示例:

class Father{

void print(){};

}


class Son extends Father{

void print(){System.out.println("子類中!");}

void show(){System.out.println("show 中!");}

}


class Demo{

public static void main(String args[]){

Father obj=new Son();

obj.print();

obj.show();  //這個調用會報錯!

}

}


1 .若是你想實現多態,那麼必須有三個條件,父類引用,子類對象,方法覆蓋

你這裏若是Fathor類有一個show()方法,那麼造成方法覆蓋,那麼此時就能夠這麼寫:obj.show(),此刻造成了多態.

2. 沒有方法覆蓋,那你這裏只能解釋爲父類引用去訪問一個子類的方法,固然,父類引用沒有這麼大範圍的權限,固然會報錯

PS:多態其實是一種機制,在編譯時刻,會生成一張虛擬表,來記錄全部覆蓋的方法,沒有被覆蓋的方法是不會記錄到這張表的.

若一個父類引用調用了沒有覆蓋的子類方法,那麼是不符合該表的,那麼編譯時刻就會報錯.

在執行程序的時候,虛擬機會去這張虛擬表中找覆蓋的方法,好比引用中實際上存的是一個子類對象引用,那麼就會去找子類中的相應的覆蓋的方法來執行

定義一個父類類型的引用指向一個子類的對象既可使用子類強大的功能,又能夠抽取父類的共性。

因此,父類類型的引用能夠調用父類中定義的全部屬性和方法,而對於子類中定義而父類中沒有的方法,它是迫不得已的;

同時,父類中的一個方法只有在在父類中定義而在子類中沒有重寫的狀況下,才能夠被父類類型的引用調用;

對多態的理解:多態體如今繼承中,因此須要有繼承關係,而後子類要重寫父類方法,最後父類指向子類(父類自己具備一些方法,這些方法被子類重寫了,但調用這些方法時,會自動調子類重寫的那些)。

多態具體表如今重寫和重載,多態就是類的多種表現方式,好比同名不一樣參,子類重寫父類。

看下面這段程序:

class Father{

    public void func1(){

        func2();

    }


    //這是父類中的func2()方法,由於下面的子類中重寫了該方法

    //因此在父類類型的引用中調用時,這個方法將再也不有效

    //取而代之的是將調用子類中重寫的func2()方法

    public void func2(){

        System.out.println("AAA");

    }

}

 

class Child extends Father{

    //func1(int i)是對func1()方法的一個重載

    //因爲在父類中沒有定義這個方法,因此它不能被父類類型的引用調用

    //因此在下面的main方法中child.func1(68)是不對的

    public void func1(int i){

        System.out.println("BBB");

    }


    //func2()重寫了父類Father中的func2()方法

    //若是父類類型的引用中調用了func2()方法,那麼必然是子類中重寫的這個方法

    public void func2(){

        System.out.println("CCC");

    }

}


public class PolymorphismTest {

    public static void main(String[] args) {

        Father child = new Child();

        child.func1();//打印結果將會是什麼?  

    }

}


  
上面的程序是個很典型的多態的例子。子類Child繼承了父類Father,並重載了父類的func1()方法,重寫了父類的func2()方法。重載後的func1(int
i)和func1()再也不是同一個方法,因爲父類中沒有func1(int i),那麼,父類類型的引用child就不能調用func1(int
i)方法。而子類重寫了func2()方法,那麼父類類型的引用child在調用該方法時將會調用子類中重寫的func2()。


    那麼該程序將會打印出什麼樣的結果呢?

    很顯然,應該是「CCC」。







變量是不存在重寫覆蓋的!

public class A { int a = 1; }

public class B extends A { int a = 2; }


測試類裏調用了這個方法void compare(){

if(super.a == this.a)

System.out.println("not overrided");

else

System.out.println("overrided");}

控制檯出來的是overrided

 類中的屬性是沒有多態性的,即你在引用上面使用屬性時,系統只會去找引用的靜態類型中的那個屬性,而與它的實際類型無關。

靜態方法也是沒有多態性的。

相關文章
相關標籤/搜索