在《java編程思想》這本書的多態(tài)的那一章中提到多態(tài)是通過動態(tài)綁定實現(xiàn)的济瓢,但具體的實現(xiàn)過程作者沒有詳細(xì)介紹。本文試圖弄清楚Java 動態(tài)綁定的實現(xiàn)原理妹卿。
本文的邏輯:什么是綁定旺矾?為什么需要綁定?綁定的分類夺克?為什么要有兩種綁定類型箕宙?每種類型的綁定分別是如何實現(xiàn)的?這種思想給了我們什么啟發(fā)铺纽?
1.綁定
面向?qū)ο蟮恼Z言中柬帕,最常見不過的就是調(diào)用實例化對象的方法,而綁定就是將方法和所在對象/類關(guān)聯(lián)起來狡门。例如陷寝,Shape s=new Shape();s.draw(); 通過綁定,當(dāng)調(diào)用draw()方法時其馏,系統(tǒng)會調(diào)用s對象的draw()方法凤跑,而不是其他對象的同名方法。至于為什么要綁定叛复,看例子也明白了仔引,通過綁定扔仓,可以方法找到自己的主人,即作用的對象咖耘。
2翘簇。綁定的分類
綁定分為靜態(tài)綁定(運行前綁定)和動態(tài)綁定(運行時綁定)。
靜態(tài)綁定:在程序運行前就明確了方法屬于哪個類鲤看,所以編譯的時候就可以找到類缘揪,進(jìn)而找到它的方法進(jìn)行編譯。
動態(tài)綁定:在程序運行中义桂,要根據(jù)實例對象的類型確定調(diào)用哪個方法找筝。
有了靜態(tài)綁定為什么還要有動態(tài)綁定?因為程序員想讓代碼的擴(kuò)展性更好(說人話:少寫點代碼慷吊,少改點bug)袖裕,所以通過實現(xiàn)動態(tài)綁定實現(xiàn)多態(tài),下面介紹動態(tài)綁定這個黑盒子中的世界溉瓶。
3. 動態(tài)綁定的實現(xiàn)
答案是:方法表急鳄。方法表這里涉及到JVM(java虛擬機(jī))加載類的具體過程,下面會安排專門的文章進(jìn)行探索堰酿,也是很有意思疾宏。不知道什么東西的可以先把它想象成一個簡單的多行兩列的表格,每一行左邊存著類的某個方法触创,右邊存的是該方法的指針(指向該方法的內(nèi)存地址坎藐,即內(nèi)存中該方法代碼塊的起始位置)。
那么想象一下多態(tài)的名場面哼绑,當(dāng)三角形類(Tri)岩馍、圓形類(Cir)繼承Shape類時,分別重寫了draw()方法抖韩。當(dāng)
Shape s1=new Tri(); s1.draw(); 被運行時蛀恩,機(jī)器準(zhǔn)確無誤地調(diào)用了三角形的draw方法。那么方法表具體是怎么做的呢茂浮?
編譯時双谆,編譯器會加載類的方法表到該類的方法區(qū)中,如果被編譯的程序中某個類的方法是在它的方法表中存在席揽,編譯就能通過佃乘。例如編譯器在編譯程序Tri t1=new Tri(); t1.erase(); 時,如果在Tri類的方法表中找到erase方法驹尼,則編譯就會通過趣避。
如果子類Tri重寫父類中的draw方法時,Tri中的方法表中的draw方法會指向它自己的draw方法的代碼塊地址新翎。
回到上文多態(tài)的名場面程帕,運行時住练,在執(zhí)行Shape s1=new Tri()時,會創(chuàng)建一個三角形對象愁拭,然后運行 s1.draw();時讲逛,JVM會把s1對象壓入操作棧,對其進(jìn)行操作岭埠。具體是找到s1對象所屬的三角形類去找draw方法盏混,找到之后進(jìn)行調(diào)用,所以調(diào)用的是三角形的draw方法惜论。