java基礎 —— 1 子父類內存控制

   

    前言
    最近在複習java基礎,作基本功,學習過程當中整理到的筆記在此用java基礎系列來和你們作分享,歡迎你們批評指正。
    



    java的繼承是三大特性封裝、繼承、多態之一,也是在個人是code中常常出現的,可是究竟在內存中子父類是如何存儲的? 子父類中一些玄妙的調用、訪問爲什麼會有這般運行結果?子父類中super和this到底應該如何運用?它們有哪些注意事項?咱們來從頭到來。
        
    首先,咱們先來搞清楚繼承的變量和方法是如何繼承的。
    

    [代碼清單 1] java

class Father{
    public int age;

    public void info(){
        System.out.println("父類的方法");
    }
}

public class Son extends Father{
	public String name;
}
    咱們知道子類Son如今應該已經擁有父類的age實例變量和info方法。可是這並非徹底擁有。
    在繼承之中,父類的非同名方法方法會直接copy到子類中,也就是說如今實際上Son代碼中已經隱式的存在父類的info方法代碼。而若是子類中存在同名的方法則編譯器不會實現父類方法copy到子類。再說變量,繼承中變量是不會被編譯器copy的,也就是說子類Son中是沒有實
例變量age的。                                                                                                          

    弄清楚上述問題,咱們來看解決一個疑惑。
    [代碼清單 2]
class Father{
		
	public int count = 10;

	public void show(){
             System.out.println(this.count);
	}
}     

class Son extends Father{
		
	public int count = 100;

	@override    //重寫標誌 強制程序員重寫此方法不然編譯時錯誤
	public void show(){
		System.out.println(this.count);
	}
}          

public class Test{

	public static void main(String[] args){
		Father f = new Father();
		System.out.println("Father類型的Father對象f:" + f.count);    A
		f.show();

		Son s = new Son();
		System.out.pritln("Son類型的Son對象s" + s.count);	B
		s.show();

		Father fs = new Son();
		System.out.println("Father類型的Son對象fs" + fs.count);	C
		fs.show();

		Father f2s = s;
		System.out.println("Father類型的Son對象f2s" + f2s.count);	D
		f2s.show();
	}
}
    看完上述代碼咱們來討論一下輸出結果。
    A處代碼,毋庸置疑,訪問父類的實例變量count輸出2,調用父類的show方法輸出2。
    B出代碼,也很明顯,訪問子類的實例變量count輸出20,調用子類的show方法輸出20。
    C處代碼,輸出結果是訪問父類的實例變量count輸出2,調用子類的show方法輸出20。此處,fs是一個Father類型的Son對象,也就是說fs 的聲明類型是Father,實際運行對象是一個Son。你能夠理解爲一個動物類型的貓對象,若是你對多態理解足夠的話,這裏不難理解。也就是說 java在引用類型變量來訪問其指向的對象的變量的時候取決於他的聲明時類型,而當在引用類型變量調用其指向的對象的方法時,取決於實際運行的對象,由於在繼承之中,父類的非同名方法方法會直接copy到子類中,可是繼承中變量是不會被編譯器轉移的。
    D處代碼,輸出結果同C處代碼。這裏須要注意的是Father f2s = s;意味着,s和f2s指向堆內的同一個對象Son s = new Son();

    到這裏,java繼承裏面的訪問和調用問題應該解決了。接下來,咱們來研究一下在堆內存中,子父類是如何儲存的。
    這以前先說一下,類在堆棧裏面如何存儲。
    1.一般引用類型變量是存儲在棧內存中的,特殊狀況是當引用類型變量做爲數組元素的時候將存儲在堆內存中。
    2.局部變量,包括基本數據類型,引用類型變量,都存放在各自的方法棧中。
    3.new 出的對象會存放在堆內存中。
    So 咱們回到初衷。當繼承發生,子類對父類的變量時如何保存的?咱們知道父類的變量不會copy到子類中,可是子類仍是能夠訪問到父類的變量,你可能會說由於繼承,或者由於super。可是實際上在內存中,但你new了一個Son的對象,注意我是說在堆內存中實際對象是一個Son,不是Son類型的Father(固然這個不容許)。這時候Son對象是隱式的存儲了Father的變量(類變量和實例變量),若是有的話還包括groundfather的變量。

    好吧,搓搓手,如今看一下隱晦的this和super,先看如下代碼想一想結果。
    [代碼清單 3]
class Father{
	String str = "父類變量";

	public Father getThis(){
		return this;
	}
	public void info(){
		System.out.println("父類方法");
	}
}

public class Son{
	String str = "子類變量";

	@override
	public void info(){
		System.out.println("子類方法");
	}
	public void showFatherInfo(){
		super.info();
	}
	public Father getFather(){
		return super.getThis();
	}
	public static void main(String[] args){
		Son s = new Son();
		Father f = s.getFather();

		System.out.println(s==f+","+s.str+","+f.str);

		s.info();
		f.info();
		s.showFatherInfo();
	}
}
    小夥伴們看到結果沒?s==f 會輸出ture,說明s和f指向同一個對象,那麼是哪一個對象呢?而後咱們看到s.str和f.str 分別輸出子類變量和父類變量。爲何?由於子類方法getFather()其實是返回了一個Father類型的Son對象。因此s.info(); 和f.info();輸出都是子類方法。s.showFarherInfo()才真正是父類的行爲方法。     最後,有幾點super的注意事項:     1.super不能夠直接用做引用變量,super == s;編譯時錯誤。     2.不能夠return super;     3.父類中的類變量能夠用super.str或者類名.str訪問。
相關文章
相關標籤/搜索