天天看點

java中靜态與動态綁定_關于java的靜态綁定與動态綁定小結

關于java的靜态綁定與動态綁定小結

一、問題

Java方法調用過程中,Jvm是如何知道調用的是哪個類的方法Jvm又是如何處理

二、概念

a、當子類和父類(接口和實作類)存在同一個方法時,子類重寫父類(接口)方法時,程式在運作時調用的方法時,是調用父類(接口)的方法呢還是調用子類的方法呢我們将确定這種調用何種方法的操作稱之為綁定。

?綁定又分為靜态綁定和動态綁定。

靜态綁定

靜态綁定是在程式執行前就已經被綁定了(也就是在程式編譯過程中就已經知道這個方法是哪個類中的方法)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

publicclassStaticBindDemo {

publicstaticvoids1() {

System.out.println("static s1");

}

privatevoidp1() {

System.out.println("private p1");

}

publicfinalvoidf1() {

System.out.println("final f1");

}

}

調用方:

1

2

3

4

5

6

7

publicclassStaticCall {

publicstaticvoidmain(String[] args) {

StaticBindDemo sbd =newStaticBindDemo();

StaticBindDemo.s1();

sbd.f1();

}

}

反編譯後的檔案:

上面的源代碼反編譯後,我們可以看到

調用的是靜态方法

1

8: invokestatic #4// Method com/jstar/jvm/sync/bind/StaticBindDemo.s1:()V

1、#4指的是常量沲中的第4個常量表索引項,記錄的是方法s1的符号引用,jvm會根據這個符号引用找到方法f1

所在的類的全限定名: com/jstar/jvm/sync/bind/StaticBindDemo

2、緊接着JVM會加載、邊接和初始化類StaticBindDemo類

3、然後在StaticBindDem類所在的方法區中找到s1()方法的直接位址,并将這個直接位址記錄到StaticCall類的常量池索引為4的常量表中。這個過程叫常量池解析 ,以後再次調用StaticBindDemo.s1時,将直接找到s1方法的位元組碼;

4、 完成了StaticCall類常量池索引項4的常量表的解析之後,JVM就可以調用s1()方法,并開始解釋執行f1()方法中的指令了。

通過上面的過程,我們發現經過常量池解析之後,JVM就能夠确定要調用的s1()方法具體在記憶體的什麼位置上了。實際上,這個資訊在編譯階段就已經在StaticCall類的常量池中記錄了下來。這種在編譯階段就能夠确定調用哪個方法的方式,我們叫做靜态綁定機制

注:Java中隻有private、static和final修飾的方法以及構造方法是靜态綁定。

a、private方法的特點是不能被繼承,也就是不存在調用其子類的對象,隻能調用對象自身,是以private方法和定義該方法的類綁定在一起。

b、static方法又稱類方法,類方法屬于類檔案。它不依賴對象而存在,在調用的時候就已經知道是哪個類的,是以是類方法是屬于靜态綁定。

c、final方法:final方法可以被繼承,但是不能被重寫,是以也就是說final方法是屬于靜态綁定的,因為調用的方法是一樣的。

?總結:如果一個方法不可被繼承或者繼承後不可被覆寫,那麼這個方法就采用的靜态綁定。

動态綁定

編譯器在每次調用方法時都要進行搜尋,時間開銷相當大。是以虛拟機會預先為每個類建立一個方發表(method table),其中列出了所有方法的簽名和實際調用的方法。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

publicclassFather {

publicvoidf1() {

System.out.println("father-f1");

}

publicvoidf1(inti) {

System.out.println("father-f1 params-int :"+ i);

}

}

publicclassSonextendsFather{

publicvoidf1() {

System.out.println("son f1");

}

publicvoidf1(charc) {

System.out.println("son-f1 params-c:"+ c);

}

}

publicclassDemo {

publicstaticvoidmain(String[] args) {

Father f =newSon();

f.f1();

//f.f1('c');

}

}

通過反編譯Demo我們來看看jvm是怎麼執行的

其中invokevirtual指令的詳細調用過程是這樣的:

(1) invokevirtual指令中的#4指的是Demo類的常量池中第4個常量表的索引項。這個常量表(Methodref) 記錄的是方法f1資訊的符号引用(包括f1所在的類名,方法名和傳回類型)。JVM會首先根據這個符号引用找到調用方法f1的類的全限定名: Father。這是因為調用方法f1的類的對象father聲明為Father類型。

(2) 在Father類型的方法表中查找方法f1,如果找到,則将方法f1在方法表中的索引項記錄到Demo類的常量池中第4個常量表中(常量池解析)。這裡有一點要注意:如果Father類型方法表中沒有方法f1,那麼即使Son類型中方法表有,編譯的時候也通過不了。因為調用方法f1的類的對象father的聲明為Father類型。

(3) 在調用invokevirtual指令前有一個aload_1指令,它會将開始建立在堆中的Son對象的引用壓入操作數棧。然後invokevirtual指令會根據這個Son對象的引用首先找到堆中的Son對象,然後進一步找到Son對象所屬類型的方法表.

(4) 這是通過第(2)步中解析完成的#4常量表中的方法表的索引項,可以定位到Son類型方法表中的方法f1(),然後通過直接位址找到該方法位元組碼所在的記憶體空間。

很明顯,根據對象(father)的聲明類型(Father)還不能夠确定調用方法f1的位置,必須根據father在堆中實際建立的對象類型Son來确定f1方法所在的位置。這種在程式運作過程中,通過動态建立的對象的方法表來定位方法的方式,我們叫做動态綁定機制。

動态綁定過程:

?<1>虛拟機提取對象的實際類型的方法表。

?<2>虛拟機搜尋方法簽名,此時虛拟機已經知道應該調用哪種方法。(PS:方法的簽名包括了:1.方法名 2.參數的數量和類型~~~~傳回類型不是簽名的一部分。)

?<3>虛拟機調用方法

轉載自https://www.cnblogs.com/xyz-star/p/10152676.html

關于java的靜态綁定與動态綁定小結 相關文章

centos7配置靜态ip位址

centos7的網絡IP位址配置檔案在 /etc/sysconfig/network-scripts 檔案夾下 進入這個檔案夾 cd /etc/sysconfig/network-scripts 使用ll指令檢視所有檔案,找到對應的網卡,我的網卡是ifcfg-ens32 [[email protected] ~]# cd /etc/sysconfig/network-scripts[root

真正讀懂jvm

一、java 檔案在jvm 中的執行過程 一、裝載1.将java檔案編譯成位元組碼檔案,位元組碼檔案是java 虛拟機可以識别的檔案2.将java 位元組碼檔案通過流的方式裝載到記憶體,也就是按照虛拟機所需的格式存儲在方法區中,同時在java 堆中生成一份java.lang.Class 對象,這

java-ArrayList源碼

ArrayLisrt 應該不陌生,對,就是可調整大小的動态數組,具體怎麼實作的呢,就讓咱們一探究竟吧! 初始化: 構造方法: 建構一個初始化容量為10的空數組 //預設初始化資料容器 private static final Object[] EMPTY_ELEMENTDATA = {};/** /* 存儲數組元素的

如何建立一個Java項目

目錄 建立項目 項目資訊配置 建立Java類 編譯和運作 建立項目 首先輕按兩下eclipse進入到eclipse頁面。 菜單“File”下的“New”裡“Java Project”,點選即可建立Java項目。 項目資訊配置 1)給項目起名稱。 2)use default location(使用預設位置),當然,你

Java并發程式設計常識

這是why的第 85 篇原創文章 寫中間件經常要做兩件事: 1.延遲加載,在記憶體緩存已附加元件。 2.統計調用次數,攔截并發量。 就這麼個小功能,團隊裡的人十有八九寫錯。 上面這句話不是我說的,是梁飛在他的部落格裡面說的。 梁飛是誰 據網上的公開資料,梁飛,花

jsp 與jstl

差別: jsp=html+java web混合 文法較為複雜難以編寫 如if語句編寫如下: body%if(flag){%h2歡迎 %=name %/h2%} %/body 需要将java語句套在% %中 jstl書寫較為簡便if語句如下: bodyjstltest brbrc:if test="${flag== true}" 歡迎${name} c:out value="${nam

Java中的集合(最全幹貨精美裝)

By CaesarChang 合作: [email protected] ~關注我 帶你看更多精品知識 類集中最大的幾個操作接口:Collection、Map、Iterator,這三個接口為以後要使用的最重點的接口。 ------------------------為了更好的學習集合 ,先簡單串一下資料結構-------------

Java實作輸入數字 n按順序列印出從 1 到最大的 n 位十進制數。比如輸入 3則列印出 1、2、3 一直到最大的 3 位數 999。

class Solution { public int[] printNumbers(int n) { int size=(int)(Math.pow(10,n)-1); int[] arrs=new int[size]; for(int i=0;isize;i++){ arrs[i]=i+1; } return arrs; }} 學會用 Math.pow(要被次方的數, 次方) ; 即可 他是double 一定要自己 (int 轉

Java輸入一個整型數組數組中的一個或連續多個整數組成一個子數組。求所有子數組的和的最大值。 要求時間複雜度為O(n)。輸入: nums = [-2,1,-3,4,-1,2,1,-5,4] 輸出:

By CaesarChang 合作: [email protected] ~關注我 帶你看更多精品知識 見注釋 簡單動态規劃問題 将前面的數之和做一個更新 class Solution { public int maxSubArray(int[] nums) { int Max=nums[0]; int pre=0; //記錄前面的和 int cur=0; //記錄目前數

Java輸入整數數組 arr 找出其中最小的 k 個數。例如輸入4、5、1、6、2、7、3、8這8個數字則最小的4個數字是1、2、3、4。

By CaesarChang 合作: [email protected] ~關注我 帶你看更多精品知識 class Solution { public int[] getLeastNumbers(int[] arr, int k) { Arrays.sort(arr); int [] arrSort=Arrays.copyOf(arr,k); return arrSort; }} 學會用Arrays.sort([ ]) 用法