執行流程
<span style="font-size:14px;">1:Animal a = new Cat();
1.1:在棧中創建區域,類型爲Animal,變量名:a;
1.2:在堆中new Cat();佔用一塊區域。地址值:[0x3a4]
1.3:spuer()實例化父類Animal。
1.3.1:new Animal();佔用一塊區域,地址值:0x3ab;
1.3.2:引用着在方法區中初始化[Animal中的所有方法,該引用爲:[0x754]]。
1.3.3:將Animal()引用賦給spuer();spuer引用着Animal();
1.4:在方法區中初始化Cat類的所有方法,引用值爲0x343。
1.5:將0x3a4賦給棧中的變量a;a就開始引用Cat()。
2:a.eat();
2.1:通過[0x3a4]找到Cat。
2.2:編譯時期:先spuer()找到Animal中的方法。如果沒有,則報錯。
2.3:運行時:直接在Cat中找到eat(),當Cat中沒有,再去Animal中找。
2.4:將eat()方法要方法區壓棧,執行,輸出:SOP(貓吃魚);
3:a = new Dog();
3.1:在堆new Dog(),開闢一塊新區域,地址值:0x87xfds
3.2:spuer();實例化父類Animal
3.2.1:new Animal()開闢新區域,地址值0x33fa;
3.2.2:成員方法引用着方法區中已初始化的[0x754];
3.2.3:將Animal地址值0x33fa賦給spuer();;spuer引用着Animal();
3.3:在方法區中初始化Dog類的所有方法,引用值爲0x422ac。
3.4:將[0x87xfds]賦給棧中的變量a; a不再引用Cat,而是引用着Dog;這時堆中的Cat已成爲垃圾,等待JVM空閒時來回收。
4:a.eat();
4.1:通過a變量引用值找到堆中標記爲0x87xfds的區域。
4.2:編譯時:先進super();去檢查Animal引用的方法區中有沒有eat()方法,如有沒有則報錯。
4.3:運行時:直接去Doa方法區中找到eat();如果Doa沒有,再去執行super()調用父類的eat()方法。
4.4:從方法區中將eat()壓棧,執行(SOP('狗吃糧'))。
5:a.shudy();
5.1:通過a變量引用值找到堆中標記爲0x87xfds的區域。
5.2:編譯時:先進super();去檢查Animal引用的方法區中有沒有shudy()方法,結果Animal中沒有shudy()方法,所以就在編譯時期就報錯。
6:Dog d = (Dog)a;
6.1:在棧中開闢區域,存儲類型爲Dog,變量名d
6.2:將a向下轉型,從Animal轉爲Dog來引用Dog;(將a變量賦給d)
6.3:a和d都指向堆中同一個Dog對象。
7:d.eat();//從Dog方法中壓棧執行eat()方法,然後彈棧;
8:d.shudy();//從Dog方法中壓棧執行shudy()方法,然後彈棧;
9:Cat c = (Cat) a;
9.1:在棧中開闢一塊區域,存儲類型:Cat,變量名稱:c
9.2:將a向下轉型,將Anmail引用Dao轉爲Cat引用Dog;結果拋出類型轉換異常。Dog不能被轉爲Cat;</span>
總結:
1:多態=繼承+重寫+父類引用子類 如: Fu ff = new Zi();
2:普通成員
變量:都參考左邊,因爲變量不存在重寫,方法中調用變量採用就近原則。
方法:編譯參考左邊,運行參考右邊。
3:靜態成員
變量和方法:編譯運行都參考左邊; 因爲靜態與對象無關。成員加靜態修飾的沒加private,都可以被類直接調用,所以參考的都是左邊。