Java 中深層理解父類引用指向子類對象


Java 中深層理解父類引用指向子類對象

從對象的內存角度來理解試試.假設現在有一個父類Father,它里面的變量需要占用1M內存.有一個它的子類Son,它里面的變量需要占用0.5M內存.現在通過代碼來看看內存的分配情況:Father f = new Father();//系統將分配1M內存.Son s = new Son();//系統將分配1.5M內存!因為子類中有一個隱藏的引用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的內存,所以無法轉換.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 類中的屬性是沒有多態性的,即你在引用上面使用屬性時,系統只會去找引用的靜態類型中的那個屬性,而與它的實際類型無關。
靜態方法也是沒有多態性的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM