首頁  >  文章  >  Java  >  java靜態綁定與動態綁定實例程式碼詳解

java靜態綁定與動態綁定實例程式碼詳解

伊谢尔伦
伊谢尔伦原創
2017-07-17 16:11:071623瀏覽

Java 靜態綁定與動態綁定

 程式綁定的概念:

#綁定指的是一個方法的呼叫與方法所在的類別(方法主體)關聯起來。對java來說,綁定分為靜態綁定和動態綁定;或者叫做前期綁定和後期綁定.

#靜態綁定:





##在程式執行前方法已經被綁定(也就是說在編譯過程中就已經知道這個方法到底是哪個類別中的方法),此時由編譯器或其它連接程式實作。例如:C。

針對java簡單的可以理解為程式編譯期的綁定;這裡特別說明一點,java當中的方法只有final,static,private和建構方法是前期綁定
  1. 動態綁定:

  2. 後期綁定:在執行時根據特定物件的類型進行綁定。

  3. 若一種語言實作了後期綁定,同時必須提供一些機制,可在運行期間判斷物件的類型,並分別呼叫適當的方法。也就是說,編譯器此時依然不知道物件的類型,但方法呼叫機制能自己去調查,找到正確的方法主體。不同的語言對後期綁定的實作方法是有所區別的。但我們至少可以這麼認為:它們都要在物件中安插某些特殊類型的信息。

動態綁定的過程:



#虛擬機器提取物件的實際類型的方法表;



虛擬機器搜尋方法簽章;


呼叫方法。

關於final,static,private和建構方法是前期綁定的理解

對於private的方法,首先一點它不能被繼承,既然不能被繼承那麼就沒辦法透過它子類別的物件來調用,而只能透過這個類別自身的物件來調用。因此就可以說private方法和定義這個方法的類別綁定在了一起。

###final方法雖然可以被繼承,但不能被重寫(覆寫),雖然子類別物件可以調用,但是調用的都是父類別中所定義的那個final方法,(由此我們可以知道將方法宣告為final類型,一是為了防止方法被覆蓋,二是為了有效地關閉java中的動態綁定)。 ###建構方法也是不能被繼承的(網路上也有說子類別無條件地繼承父類別的無參數建構函數作為自己的建構函數,不過個人認為這個說法不太恰當,因為我們知道子類別是透過super( )來呼叫父類別的無參構造方法,來完成對父類別的初始化, 而我們使用從父類別繼承過來的方法是不用這樣做的,因此不應該說子類別繼承了父類別的建構方法),因此編譯時也可以知道這個構造方法到底是屬於哪個類別。 #########對於static方法,具體的原理我也說不太清。不過根據網路上的資料和我自己做的實驗可以得出結論:static方法可以被子類別繼承,但是不能被子類別重寫(覆蓋),但是可以被子類別隱藏。 (這裡意思是說如果父類別裡有一個static方法,它的子類別裡如果沒有對應的方法,那麼當子類別物件呼叫這個方法時就會使用父類別中的方法。而如果子類別中定義了相同的方法,則會呼叫子類別的中定義的方法。的靜態方法。 因此這裡說靜態方法可以被隱藏而不能被覆寫。存取父類別被隱藏的變數和方法,而不能存取父類別被覆寫的方法)#########由上面我們可以得出結論,如果一個方法不可被繼承或繼承後不可被覆蓋,那麼這個方法就採用的靜態綁定。 #########java的編譯與執行############java的編譯過程是將java原始檔編譯成字節碼(jvm可執行程式碼,即.class文件)的過程,在這個過程中java是不與記憶體打交道的,在這個過程中編譯器會進行語法的分析,如果語法不正確就會報錯。 ######

Java的運作過程是指jvm(java虛擬機器)裝載字節碼檔案並解釋執行。在這個過程才是真正的創立記憶體佈局,執行java程式。
java字節碼的執行有兩種方式: (1)即時編譯方式:解釋器先將位元組編譯成機器碼,然後再執行該機器碼;(2)解釋執行方式:解釋器透過每次解釋並執行一小段程式碼來完成java字節碼程式的所有操作。 (這裡我們可以看出java程式在執行過程中其實是進行了兩次轉換,先轉成字節碼再轉換成機器碼。這也正是java能一次編譯,到處運行的原因。在不同的平台上裝上對應的java虛擬機,就可以實現相同的字節碼轉換成不同平台上的機器碼,從而在不同的平台上運行)

#前面已經說了對於java當中的方法而言,除了final,static,private和構造方法是前期綁定外,其他的方法全部為動態綁定。
而動態綁定的典型發生在父類別和子類別的轉換宣告之下:

例如:Parent p = new Children();

其具體過程細節如下:

1:編譯器檢查物件的宣告型別和方法名。

假設我們呼叫x.f(args)方法,並且x已經被宣告為C類別的對象,那麼編譯器會列舉出C 類別中所有的名稱為f 的方法和從C 類別的超類別繼承過來的f 方法。

2:接下來編譯器檢查方法呼叫中提供的參數類型。

如果在所有名稱為f 的方法中有一個參數型別和呼叫提供的參數型別最為匹配,那麼就呼叫這個方法,這個過程叫做「重載解析」。

3:當程式運作並且使用動態綁定呼叫方法時,虛擬機器必須呼叫相同x所指向的物件的實際類型相符的方法版本。

假設實際類型為D(C的子類別),如果D類別定義了f(String)那麼該方法被調用,否則就在D的超類別中搜尋方法f(String) ,依次類推。
JAVA 虛擬機器呼叫一個類別方法時(靜態方法),它會基於物件引用的類型(通常在編譯時可知)來選擇所呼叫的方法。相反,當虛擬機器呼叫一個實例方法時,它會基於物件實際的類型(只能在運行時得知)來選擇所呼叫的方法,這就是動態綁定,是多態的一種。動態綁定為解決實際的業務問題提供了很大的靈活性,是一種非常優美的機制。

與方法不同,在處理java類別中的成員變數(實例變數和類別變數)時,並不是採用執行時間綁定,而是一般意義上的靜態綁定。所以在向上轉型的情況下,物件的方法可以找到子類,而物件的屬性(成員變數)還是父類別的屬性(子類別對父類別成員變數的隱藏)。


public class Father { 
  protected String name = "父亲属性"; 
}   
public class Son extends Father { 
  protected String name = "儿子属性"; 
  
  public static void main(String[] args) { 
    Father sample = new Son(); 
    System.out.println("调用的属性:" + sample.name); 
  } 
}

結論,呼叫的成員為父親的屬性。

這個結果表明,子類別的物件(由父類別的引用handle)呼叫到的是父類別的成員變數。所以必須明確,運行時(動態)綁定針對的範疇只是物件的方法。

現在試圖呼叫子類別的成員變數name,該怎麼做?最簡單的辦法是將該成員變數封裝成方法getter形式。
程式碼如下:


public class Father { 
  protected String name = "父亲属性"; 
  public String getName() { 
    return name; 
  } 
}   
public class Son extends Father { 
  protected String name = "儿子属性"; 
  public String getName() { 
    return name; 
  } 
  public static void main(String[] args) { 
    Father sample = new Son(); 
    System.out.println("调用的属性:" + sample.getName()); 
  } 
}

結果:呼叫的是兒子的屬性

##java因為什麼對屬性要採取靜態的綁定方法。這是因為靜態綁定是有很多的好處,它可以讓我們在編譯期就發現程式中的錯誤,而不是在運行期。這樣就可以提高程式的運作效率!

以上是java靜態綁定與動態綁定實例程式碼詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn