天天看點

Java關于方法調用的了解(涉及JVM)

方法調用的過程就是找方法的過程,在完全了解java方法調用過程之前,我們需要知道一些額外的知識:    

    首先,我們對java世界中的所有方法進行分類:虛方法以及非虛方法。

        非虛方法:靜态方法(static修飾),私有方法(private修飾),父類方法,構造方法,final方法。

        虛方法:不屬于以上五種類型的方法都是虛方法。

    其次,我們再了解一下java世界中方法的存在方式:

        在java類尚未加載的時候,方法以位元組碼的形式存在于class常量池(一塊專屬的存儲區域的名稱)中。

        在java類加載之後,方法體以位元組碼的形式存在于常量池(記憶體中一塊存儲區域的名稱)中該方法對應的方法表的Code屬性中。同時,該方法的符号引用(方法名稱+方法描述符)存在于記憶體中方法區的運作時常量池中,該符号引用指向了方法體的實體位址。

        這段話有些難懂?可以将計算機記憶體想象成一個倉庫,倉庫(記憶體)的一塊區域用來暫時存放集裝箱(方法),集裝箱裡面存放着大量的物品(即該方法對應的具體代碼),每個集裝箱上都有一個辨別(該方法的符号引用)。倉庫門口有一張記錄表(運作時常量池),裡面記錄了大量的集裝箱辨別(方法的符号引用),記錄表中每個辨別還有一個項目用來記錄這些辨別代表的集裝箱所在的位置(例如:RS939号集裝箱位于倉庫東區12排9列第三層,這個“RS939”代表着方法的符号引用,而“東區12排9列第三層”代表方法在記憶體中的實體位址)。

        類加載的過程相當于将集裝箱存入倉庫的過程,在這個時候,如果這個集裝箱代表着一個非虛方法,那麼在集裝箱存入的過程中,就可以填寫記錄表,記錄下集裝箱标号以及集裝箱所在的具體位置(将符号引用轉換成直接引用),因為這些集裝箱是獨一無二的,它們色彩鮮豔且各不相同,你能夠直接在倉庫中找到他們。然而對于某些集裝箱來說(虛方法),它們外形上相似(此處為合理假設~),僅僅通過标号并不足以留下準确的記錄,需要更多的條件來判斷它們的具體位置,這些集裝箱就需要先存入倉庫中,但是它們隻會在記錄表上留下辨別而不會填寫集裝箱位置,直到程式運作時才能判斷出它們的具體位置,即在運作時才能将符号引用指向具體的方法實體位址。

        以上同時也提到了方法調用,方法調用相當于從倉庫中找到對應的集裝箱的過程。對于非虛方法的調用十分簡單,因為這些集裝箱的位置都已經十分明了的寫在記錄表上(符号引用已經轉化成直接引用),是以很容易就可以找到這些集裝箱。但是對于java中的虛方法,記錄表上并沒有這些集裝箱的位置,我們如何找到它呢?

        java是一門靜态多分派,動态單分派的語言。java代碼在編譯的時候,會先判斷方法的種類(虛方法或者非虛方法),如果是非虛方法,則根據方法的參數,方法的使用者對象(方法參數以及方法的使用對象稱為方法的宗量)直接将方法對應的符号引用轉化為直接引用,編譯期屬于靜态,而且判斷條件(宗量)有多個,是以是多分派。如果是虛方法,則要等到運作時,在調用虛方法的時候,根據對象所屬的實際類型決定要調用哪一個類的方法,這是動态的,而且判斷依據僅僅是根據對象的實際類型,單分派。

        又看不懂了?依舊是集裝箱和倉庫的例子。

        對于那些虛方法的集裝箱,由于箱子上還記錄了箱子的産地(即方法所在的類名),是以在取這些集裝箱的時候,要根據顧客需要(即對象的實際類型)來确定究竟需要哪一個産地的集裝箱,直到這個時候,記錄表上的辨別後面才會記錄集裝箱地點(将符号引用轉換成直接引用)。

        綜上,java的方法調用基本上就是如此了,如有錯誤還請指正~