方法呼叫過程(一)
方法的呼叫不等同於方法執行,方法呼叫階段唯一的任務就是確定被呼叫方法的版本(即呼叫哪一個方法),暫時還不涉及方法內部的具體執行過程。
一切方法呼叫在Class檔案裡面儲存的都只是符號引用,而不是方法在實際執行時記憶體佈局的入口地址(入口地址相當於直接引用),需要在類載入期間甚至到執行期間才能確定目標方法的直接引用。
通過javap -verbose+類名 可以看到,Java虛擬機器中提供了四條方法呼叫位元組碼指令,
1.invokestatic 呼叫靜態方法
2.invokespecial 呼叫例項構造器(init)方法、私有方法和父類方法
3.invokevirtual 呼叫所有的虛方法
4.invokeinterface 呼叫介面方法,會在執行時再確定一個實現此介面的物件
先來看下面兩種方法呼叫方式:
解析呼叫:方法在程式真正執行前就有一個可確定的呼叫版本,並且這個方法的呼叫版本在執行期是不可改變的。換句話說,呼叫目標在程式程式碼寫好、編譯器進行編譯時就必須確定下來。(一定是靜態的)
分派呼叫:方法在程式執行期間才確定呼叫版本,分派呼叫分為靜態分派和動態分派
再來理解一個概念:
非虛方法
虛方法:與之相反的,在執行期才能確定方法呼叫版本。
所以非虛方法都是通過解析呼叫(靜態),而虛方法都是通過分派呼叫(靜態或者動態)。
那麼在分派和解析呼叫中的靜態和動態的概念又怎麼理解呢,請看下面這個例子:
Human person = new Man();
Man是Human的一個子類,那麼Human就是例項person的靜態型別,Man是person的實際型別。
1.下面這段程式碼演示了方法過載(overload)時是通過靜態分派的:
public class StaticDispatch { static abstract class Human{ } static class Man extends Human{ } static class Woman extends Human{ } public void sayHello(Human m) { System.out.println("hello, guy!"); } public void sayHello(Man m) { System.out.println("hello, man!"); } public void sayHello(Woman m) { System.out.println("hello, woman!"); } public static void main(String[] args) throws Exception { Human man = new Man(); Human woman = new Woman(); StaticDispatch t = new StaticDispatch(); t.sayHello(man); t.sayHello(woman); } }
執行結果是:
hello, guy!
hello, guy!
2.下面這段程式碼演示了方法重寫(overwrite)時是動態分派的:
public class DynamicDispatch {
static abstract class Human{
protected abstract void sayHello();
}
static class Man extends Human{
@Override
protected void sayHello() {
System.out.println("hello, man!");
}
}
static class Woman extends Human{
@Override
protected void sayHello() {
System.out.println("hello, woman!");
}
}
public static void main(String[] args) {
Human man = new Man();
Human woman = new Woman();
man.sayHello();
woman.sayHello();
}
}
執行結果是:
hello, man!
hello, woman!
接下來看以下invokevirtual指令呼叫方法的過程就可以理解為什麼如此了:
(1)找到運算元棧頂的第一個元素所指向的物件的實際型別,記作C
(2)如果在型別C中找到與常量中描述符和簡單名稱都相符的方法,則進行訪問許可權校驗,如果通過則返回這個方法的直接引用,查詢結束;不通過,返回IllegalAccessError
(3)否則,按照繼承關係從下往上依次對C的各個父類進行第2步的搜尋和驗證過程
(4)始終沒有找到合適的方法,則丟擲AbstractMethodError
其實方法的過載和重寫區別就是過載依賴傳入方法的形參來區別,而重寫依賴方法呼叫者的型別來區別。
在第一步中C就是方法的呼叫者,這裡查詢的是實際型別,這就是overwrite的原理,
在第二步中查詢方法是通過描述符和簡單名稱來進行的,而傳入引數的描述符是通過靜態型別定義的,所以程式碼一會出現這樣的結果
總結一句話,過載看靜態型別,重寫看實際型別。
相關推薦
方法呼叫過程(一)
方法的呼叫不等同於方法執行,方法呼叫階段唯一的任務就是確定被呼叫方法的版本(即呼叫哪一個方法),暫時還不涉及方法內部的具體執行過程。 一切方法呼叫在Class檔案裡面儲存的都只是符號引用,而不是方法在實際執行時記憶體佈局的入口地址(入口地址相當於直接引用
Oracle中建立儲存過程和呼叫過程(一)
1、定義 所謂儲存過程(Stored Procedure),就是一組用於完成特定資料庫功能的SQL語句集,該SQL語句集經過 編譯後儲存在資料庫系統中。在使用時候,使用者通過指定已經定義的儲存過程名字並給出相應的儲存過程引數 來呼叫並執行
jquery中append、prepend, before和after方法的區別(一)
mod serve com oos 兄弟節點 sha pos 插入 5% 原文:http://blog.csdn.net/woosido123/article/details/64439490 在 jquery中append() 與 prepend()是在元素內插
Kubernetes(K8s)安裝部署過程(一)--證書安裝
更改 目錄 hand /etc 主題 nbsp kubecon 安裝部署 post 一、安裝前主題環境準備 1、docker安裝 建議使用官網yum源安裝,添加yum源之後,直接yum install docker即可 2、關閉所有節點的selinux
Web滲透學習過程(一)
滲透什麽是struts2? Struts2是一個基於MVC設計模式的Web應用框架,它本質上相當於一個servlet,在MVC設計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數據交互。其被普遍應用於阿裏、京東等各大網站。 本次講的struts2漏洞是什麽? S2-016 S2-
如何多快好省的建設企業級呼叫中心(一)
呼叫中心 呼叫中心自建 企業級呼叫中心 前幾天,之前好大夫在線的一位開發同事咨詢我一些關於搭建呼叫中心的事宜,簡單溝通後還吹了個牛說自己可以隨時去分享一些關於呼叫中心建設的經驗和心得……再加上之前一些運營部門的同事也經常咨詢我一些關於呼叫中心選型和建設的的一些問題,終於讓我決定整理
記錄自己用python搭建個人部落格系統的完整過程(一)
零、前言 本博文記錄搭建個人部落格系統的完整過程,網上有許多相關的教程,但是沒找到一個(適合自己能力的)快速搭建的完整教程。藉此篇博文梳理一下前不久學習到的有關整個過程前前後後的各種知識點。 一、搭建環境 採用架構:python3.6 + django1.10 + ngi
PostgreSQL+REDIS_FDW詳細記錄踩坑過程(一)
案例環境: 虛擬機器:CenterOS 7.0.1406(注意:centerOS自帶postgres9.2的版本安裝包) PG版本:postgresql-10.5-1-linux-x64-binaries.tar.gz redis_fwd版本:redis_fdw-REL_10_STABL
web資料匯出到Excel的步驟方法及糾錯(一)
頁面HTML程式碼寫法——新增到處Excel按鈕 <input type="button" ng-click="exports0()" value="匯出Excel"> selectController.js ——新增內容 //資料匯出到excel $sco
java基礎之----基本資料型別和引用資料型別的引數傳遞過程(一)
值傳遞:方法呼叫時,實際引數把它的值傳遞給對應的形式引數,方法執行中形式引數值的改變不影響實際引數的值。 引用傳遞:也稱為傳地址。方法呼叫時,實際引數的引用(地址,而不是引數的值)被傳遞給方法中相對應的形式引數,在方法執行中,對形式引數的操作實際上就是對實際引
hadoop啟動過程(一) NameNode
一、第一次啟動 NameNode 記憶體 本地磁碟 fsimage edits 格式化HDFS,目的是審查隔行fsimage
YOLO學習過程(一)
一.下載Darknet框架並測試 1.下載編譯Darknet框架 1)終端輸入命令 git clone https://github.com/pjreddie/darknet cd darknet 2)若沒有配置GPU,CUDA及OPENCV等環境則直接輸入命令
Centos7配置ThinkPHP5.0完整過程(一)
在Centos中配置PHP伺服器環境,首先要安裝Apache的http服務,然後安裝php解析環境,最後再配置ThinkPHP5.0。 首先安裝HTTP sudo yum install httpd -y 安裝時需要管理員許可權,所以需要使用sudo。安裝之後,啟動httpd服務 sudo s
AXIS呼叫webservice(一)
public static String startWebService(String url,String operation,String account,String key,String xml){ String result = ""; try {
OC-RunTime 傳送訊息過程(一)
廢話少說,直接上乾貨。 1、首先用X-code建立一個工程選擇->macOS->Command Line Tool->填寫工程名稱oc -info。 2、建立完成後會有一個main.m檔案,在檔案內看到如下程式碼: #import <Founda
MySQL事務提交過程(一)
mysql_execute_command trans_commit_stmt ha_commit_trans(thd, FALSE); { TC_LOG_DUMMY:ha_commit_low ha_commit_low() innoba
爬蟲資料提取方法詳解(一)
爬蟲中資料的分類:結構化資料(json,xml等)處理方式是直接轉化為python型別,jsonpath,xpath,bs4等. 非結構化資料(HTML)處理方式是正則表示式,xpath,bs4等. 資料提取
webpack4.x配置過程(一)
從 webpack v4.0.0 開始,可以不用引入一個配置檔案。然而,webpack 仍然還是高度可配置的。在開始前你需要先理解四個核心概念:入口(entry),輸出(output),loader,外掛(plugins),其次還有就是mode(模式)。 以下是官方文件解析: ent
VB學習過程(一)在win7系統下VB6.0的安裝
一直想自學一下VB語言,但是沒時間,最近決定每晚花出一定時間來學習。寫部落格一是為了督促自己堅持,二是為了和大家一起分享一下學習VB的過程。 要想學習VB,第一件事就是安裝VB的程式設計軟體:VB6.0。 但是VB6.0 只能裝在XP系
[轉]HTTPS網路流量解密方法探索系列(一)
前言 分析網路流量總是繞不開HTTPS,因其廣泛使用甚至是強制使用逐漸被大眾熟知,在保證其安全的同時也提高了對流量進行研究的難度。目前解析HTTPS協議的文章很多,有很多不錯的文章可以帶著入門,老實說,HTTPS協議還是挺複雜的,尤其是握手交換金鑰的過程;雖然大部分的文章只是對協議握手的過程做了詳細的解析,