关于java中多态的理解,涉及到内存空间
其實理解了程序在內存里如何搞,如何玩,是很爽的。
首先簡要說明下程序運行時,內存的結構。堆區棧區,常量區,靜態方法區和非靜態方法區。
1.棧:存放基本類型的變量數據和對象的引用(也就是在new對象時左邊那一塊),但是對象本身不放在棧中,而是存在堆(new出來的對象)。棧中的數據大小和生命周期是可以確定的,當沒有引用指向數據時,這個數據就會消失。
2.堆:存放new出來的對象。堆中的對象由垃圾回收器負責回收,因此大小和生命周期不需要確定。
3.常量區:存放字符串常量和基本類型常量。
代碼示例:
[java]?view plaincopy
內存圖簡要示例
分析:
1.我們知道類的非靜態成員函數,都是得靠類的對象來調用的,也就是所謂的this.。那么在這句
Fu ff=new Zi();
ff.method1();
當我們aa.method1()-->this.method1()-->(new Zi()).method1().aa確實是指向Zi類的對象,method1()在運行時一定是被對象調用執行,而不是aa,因為他打印的時候或者訪問的時候是訪問對象中的那些數據。
2.而靜態方法就不同了,他本身不訪問對象特有數據。當Fu類和Zi類被加載到內存的時候,靜態方法區就已經在里面啦,并且綁定在這個方法所屬的類上面了,所以他們只直接用類名可以調用,也就是所謂的靜態綁定。他找的是靜態區的方法,不參考右邊的對象。所以
aa.method3();
只參考這個引用型變量aa是誰的。
總結:
1.編譯時期:參考應用型變量所屬的類中是否有調用的方法。如果有,編譯通過,如果沒有,編譯失敗。
2.運行時期:參考對象(new出來的對象)所屬的類中是否有調用的方法。(動態綁定)
也就是:成員函數在多臺調用時,編譯看左邊,運行看右邊。
3.多態中,成員變量的特點:無聊編譯運行,都參考左邊(引用型變量所屬的類)。
4.多態中,靜態函數的特點:無聊編譯運行,都參考左邊。(靜態綁定)
再舉個例子來說明編譯時(javac)和運行時(java)的區別,代碼如下:
[java]?view plaincopy
結果:編譯通過,運行掛掉
分析:equals是所有類的超類Object的方法,我們把他復寫掉,調用equals時,參數 Object d=new Person()這里發生了向上轉型,接著
Demo a=(Demo)d 編譯的時候是不會出錯的,因為此處的d引用變量是綁定的Object這個類;而運行的時候,發生動態綁定也就綁定到了Person類上,把Person類的對象轉化成Demo類的對象,出現類型轉換錯誤。
改正:
加上 if(!d instanceof Demo) return ;
判斷一下即可.
?多態(polymorphism):在執行期間(而非編譯器)判斷所引用對象的實際類型,根據其實際的類型調用其相應的方法。由于是在運行期的動態實現,直到new出對象才能確定具體調用的哪個方法,因此多態又叫動態綁定,也叫遲綁定。
?? 實現條件
????????????????1.類之間繼承或者實現接口;
??????????? 2.方法重寫;
??????????? 3.父類引用指向子類對象。
?? 練習
???????????????????貓、狗類實現抽象類動物的enjoy()方法,main方法中實現enjoy()方法的動態調用。
??????????? 代碼實現:
abstract class Animal {private String name;Animal(String name) {this.name = name;}public abstract void enjoy(); }class Cat extends Animal {private String eyescolor;Cat(String name,String eyescolor) {super(name);this.eyescolor = eyescolor;}public void enjoy() {System.out.println("貓叫聲。。。");} }class Dog extends Animal {private String furcolor;Dog(String name,String furcolor) {super(name);this.furcolor = furcolor;}public void enjoy() {System.out.println("狗叫聲。。。");} } /* class Bird extends Animal {Bird() {super("bird");}public void enjoy() {System.out.println("鳥叫聲。。。");} } */class Lady {private String name;private Animal pet;Lady(String name, Animal pet) {this.name = name;this.pet = pet;}public void myPetEnjoy() {pet.enjoy();} }public class Test {public static void main(String[] args) {Dog g = new Dog("mydog","black");Cat c = new Cat("mycat","blue");Bird b = new Bird();Lady l1 = new Lady("l1",g);Lady l2 = new Lady("l2",c);//Lady l3 = new Lady("l3",b);l1.myPetEnjoy();l2.myPetEnjoy();//l3.myPetEnjoy();} }
???????????????運行結果:
?????????????? 內存分析:
?????????????????
?????????????stack中存放臨時變量,heap中存放new出的實例對象,為簡單起見,圖中略去了代碼中Dog類對象以及相應的l1對象。
??????? 多態的實現是通過調用方法為運行時動態生成的Cat對象指向的Cat:enjoy()方法實現。
特性:
??????? 多態的存在能夠更好的讓我們去實現代碼的可擴展性(具體練習中可將Bird類、main方法的注釋去掉,則會在無需修改其他類的情況下實現鳥叫聲的擴展),大大提高了我們程序的靈活性。
總結:
????????多態在之前已有過學習,但理解并不是深入,通過這次學習的相應內存分析,還是深刻了很多,對內存也有過一些了解,但之前并沒有將這兩方面的學習聯系起來,分析內存對程序的運行過程有了進一步的了解。
總結
以上是生活随笔為你收集整理的关于java中多态的理解,涉及到内存空间的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java学习之多态
- 下一篇: java基础之堆、栈、方法区 继承 多态