執行流程
<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,都可以被類直接調用,所以參考的都是左邊。