日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 多态实现的jvm调用过程_多态:JVM是如何进行方法调用的

發(fā)布時間:2025/3/12 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 多态实现的jvm调用过程_多态:JVM是如何进行方法调用的 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

在我們平時的工作學習中寫java代碼時,如果我們在同一個類中定義了兩個方法名和參數(shù)類型都相同的方法時,編譯器會直接報錯給我們。還有在代碼運行的時候,如果子類定義了一個與父類完全相同的方法的時候,父類的方法就會被覆蓋,(也就是我們平時說的重寫)。那么,jvm虛擬機是如何精確識別目標方法的。

重載、重寫與多態(tài)

重載:方法名相同而參數(shù)類型不相同的方法之間的關系。

重寫:方法名相同并且參數(shù)類型也相同的方法之間的關系。

這兩個概念我們耳熟能詳,那么重載和重寫是如何判斷的呢?

重載:

重載的方法在編譯期間就可以完成識別。java編譯器會根據(jù)所傳入?yún)?shù)的聲明類型對方法名相同的方法進行選取。

除了同一個類中,如果A繼承了B,A中定義了與B中的非私有方法同名的方法,而且這兩個方法的參數(shù)類型不同,那么A和B類同樣構成了重載

重寫:

重寫方法的判斷是在運行期間才可以完成識別的。

我們都知道多態(tài)是java面向?qū)ο笳Z言的三大特性之一。而方法的重寫,就是最能體現(xiàn)多態(tài)的一種方式:它允許子類在繼承父類部分特性的同時,擁有自己獨特的行為。

舉個簡單的例子幫大家理解一下多態(tài):

比如我們按下b這個鍵,在dota中代表的是敵法師的blink技能,在lol中是回城,在網(wǎng)游里又成了背包。對于不同的對象擁有不同的行為,這就是多態(tài)。

靜態(tài)綁定與動態(tài)綁定

接下來,我們來看一下jvm是如何識別目標方法的。

剛才我們說到,重載方法的區(qū)分在編譯階段已經(jīng)完成了,那么我們就可以認為在java虛擬機中不存在重載這一概念。因此,重載也可以被稱為靜態(tài)綁定,而重寫則被稱為動態(tài)綁定。

在jvm中,我們有5種方法調(diào)用的指令,分別是:

invokestatic:調(diào)用靜態(tài)方法;

invokespecial:調(diào)用實例構造方法,私有方法和父類方法,以及使用super關鍵字調(diào)用父類的實例方法或構造器;

invokevirtual:調(diào)用虛方法(非私有實例方法);

invokeinterface:調(diào)用接口方法,在運行時再確定一個實現(xiàn)此接口的對象;

invokedynamic:在運行時動態(tài)解析出調(diào)用點限定符所引用的方法之后,調(diào)用該方法(jdk1.8lamada表達式);

這里,我們簡單介紹一下這幾種指令,對于invokestatic指令和invokespecial指令而言,java虛擬機能夠直接識別目標方法,也就是我們所說的靜態(tài)綁定。

invokevirtual和invokeinterface指令則需要在執(zhí)行的過程中才能找到目標方法,也就是我們所說的動態(tài)綁定。

總結一下靜態(tài)綁定和動態(tài)綁定的概念就是:

靜態(tài)綁定:在程序執(zhí)行之前就已經(jīng)被綁定、也就是說再編譯階段就已經(jīng)知道這個方法是屬于哪個類的方法。

1.private修飾的方法,不能被子類調(diào)用? ?2.? 被final修飾的方法? ? ? 3.被static修飾的方法

動態(tài)綁定:在運行過程中根據(jù)調(diào)用者的動態(tài)類型來識別目標方法的情況。

動態(tài)綁定中,我們會記錄方法對應的實際引用的地址,也可以理解為索引值,這里我們把它叫做方法表。

方法表使用了數(shù)組的數(shù)據(jù)結構,每個數(shù)組元素指向了當前類以及其祖先類中非私有的實例方法。

這個數(shù)據(jù)結構,便是java虛擬機實現(xiàn)動態(tài)綁定的關鍵所在

虛方法

通過這些指令的描述,我們發(fā)現(xiàn)虛方法和非虛方法直接決定了靜態(tài)綁定還是動態(tài)綁定,也就決定了是直接用父類的方法還是動態(tài)地用子類重寫的方法。所以,我們有必要去理解虛方法,并能判斷哪些是屬于虛方法。

我們先一起看兩段代碼:

代碼1:class Dota {private void play() {System.out.println("我喜歡玩dota,哈哈哈~~~");}void startGame() {play();}}?class LoLextends Dota {void play() {System.out.println("我喜歡玩lol,哈哈哈~~~~");}}?public class Demo1{public static void main(String[]args){new LoL().startGame();}}

代碼二:class Dota {void play() {System.out.println("我喜歡玩dota,哈哈哈~~~");}?void startGame() {play();}}?class LoLextends Dota {void play() {System.out.println("我喜歡玩lol,哈哈哈~~~~");}}?public class Demo2{public static void main(String[]args){new LoL().startGame();}}

這里,dota是lol的父類(本人是dotaer,哈哈),這兩段代碼的唯一不同就是代碼1的父類的play方法private修飾的,而代碼2中的play()方法不是私有的。接下來,我們看下輸出結果:

代碼1:我喜歡玩dota,哈哈哈~~~

代碼2:1我喜歡玩lol,哈哈哈~~~~

第一段代碼直接調(diào)用了父類的play()方法,而第二段代碼調(diào)用了子類的play()方法

大家是不是覺得很奇怪,一個私有的修飾符就能使結果不一樣嗎?

結合我們之前所說的進行判別,第一段代碼應該是靜態(tài)綁定,第二段代碼則是動態(tài)綁定

那么,代碼1就是非虛函數(shù),代碼2是虛函數(shù)。接下來,我們來看下虛函數(shù)的概念:

虛函數(shù):除了靜態(tài)方法之外,聲明為final或者private的實例方法是非虛方法。其它(其他非private方法)實例方法都是虛方法。

當子類對象調(diào)用重寫的方法時,調(diào)用的是子類的方法,而不是父類中被重寫的方法。

要想調(diào)用父類中被重寫的方法,則必須使用關鍵字super。

代碼1由于是private修飾,所以為非虛函數(shù),調(diào)用了invokespecial指令。

代碼2是虛函數(shù),則調(diào)用了invokevirtual指令。

再看一個例子

代碼3:

public?class?Demo2?{????static?abstract?class?Game?{}????static?class?Dota?extends?Game?{}????static?class?Lol?extends?Game?{}????public?void?play(Game?game)?{

System.out.println("hello,game");

}????public?void?play(Dota?dota)?{

System.out.println("hello,Dota");

}????public?void?play(Lol?lol)?{

System.out.println("hello,lol");

}????public?static?void?main(String[]?args)?{

Game?dota?=?new?Dota();

Game?lol?=?new?Lol();

Demo2?sd?=?new?Demo2();

sd.play(dota);

sd.play(lol);

}

}

輸出結果:hello,game

hello,game

雖然在這里,play方法是虛方法,是動態(tài)綁定,但是調(diào)用play方法的是Demo2的實例sd,由于Demo2方法沒有子類,所以不需要考慮,則直接執(zhí)行父類的方法。

總結:

我們介紹了java虛擬機(jvm)是如何執(zhí)行方法的,我們從我們熟悉的重載和重寫切入,了解了靜態(tài)綁定和動態(tài)綁定的概念:

靜態(tài)綁定:在程序執(zhí)行之前就已經(jīng)被綁定、也就是說再編譯階段就已經(jīng)知道這個方法是屬于哪個類的方法。

動態(tài)綁定:在運行過程中根據(jù)調(diào)用者的動態(tài)類型來識別目標方法的情況

并且知道了jvm中用方法表來維護非私有實例方法與其索引值的對應關系來實現(xiàn)動態(tài)綁定。

接著,我們了解了jvm中調(diào)用方法的5個指令,并且通過靜態(tài)綁定和動態(tài)綁定的概念對其進行歸類,

靜態(tài)綁定:

invokestatic:調(diào)用靜態(tài)方法;

invokespecial:調(diào)用實例構造方法,私有方法和父類方法;

動態(tài)綁定:

invokevirtual:調(diào)用虛方法;

invokeinterface:調(diào)用接口方法,在運行時再確定一個實現(xiàn)此接口的對象;

invokedynamic:在運行時動態(tài)解析出調(diào)用點限定符所引用的方法之后,調(diào)用該方法;

歸類中通過虛函數(shù)的概念,使我們對jvm中方法的調(diào)用加以更深的了解。

虛函數(shù):除了靜態(tài)方法之外,聲明為final或者private的實例方法是非虛方法。其它(其他非private方法)實例方法都是虛方法。

總結

以上是生活随笔為你收集整理的java 多态实现的jvm调用过程_多态:JVM是如何进行方法调用的的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。