java學習之編譯時類型(前期綁定)和運行時類型 (後期綁定、動態綁定、運行時綁定)

編譯時類型和運行時類型:  java

    Java的引用變量有兩個類型,一個是編譯時類型,一個是運行時類型,編譯時類型由聲明該變量時使用的類型決定,運行時類型由實際賦給該變量的對象決定若是編譯時類型和運行時類型不一致,會出現所謂的多態。由於子類實際上是一種特殊的父類,所以java容許把一個子類對象直接賦值給一個父類引用變量,無須任何類型轉換,或者被稱爲向上轉型,由系統自動完成。this

    引用變量在編譯階段只能調用其編譯時類型所具備的方法,但運行時則執行它運行時類型所具備的方法,所以,編寫Java代碼時,引用變量只能調用聲明該變量所用類裏包含的方法。與方法不一樣的是,對象的屬性則不具有多態性。經過引用變量來訪問其包含的實例屬性時,系統老是試圖訪問它編譯時類所定義的屬性,而不是它運行時所定義的屬性。spa

 —— 以上摘自《瘋狂Java講義》設計

前期綁定和後期綁定(動態綁定、運行時綁定):code

綁定:將一個方法調用同方法主體關聯起來叫作綁定對象

前期綁定:在程序執行以前進行綁定(若是有的話,由編譯器和鏈接器完成),前期綁定是面向過程程序設計語言中默認的綁定方式,例如,C語言只有一種方法調用,那就是前期綁定。get

後期綁定:就是在程序運行時根據對象的類型進行綁定,也叫做動態綁定或運行時綁定。編譯器


注意:Java中除了static和final方法(private方法屬於final方法,由於類中的private方法被隱式指定爲final方法)以外,其餘方法都是後期綁定。這意味着一般沒必要斷定是否該進行後期綁定,由於它是自動發生的。編譯

下面舉例說明:程序設計

1.子類方法覆蓋父類方法( 子類重寫父類中的方法,調用子類中的方法)

class Father{
      public void method(){
          System.out.println("父類方法:"+this.getClass());
      }
 }
 public class Son extends Father{
	public void method(){
          System.out.println("子類方法:"+this.getClass());
      }
	public static void main(String[] args){
		Father instance = new Son();
		instance.method();
	}
}
運行結果:子類方法:class Son

2. 子類沒有重寫父類中的方法,因此到父類中尋找相應的方法

class Father{
      public void method(){
          System.out.println("父類方法:"+this.getClass());
      }
 }
 public class Son extends Father{
      public static void main(String[] args){
		Father instance = new Son();
		instance.method();
	}
}
運行結果: 父類方法: class Son

3.動態綁定只是針對對象的方法,對於屬性無效。由於屬性不能被重寫。

class Father{
     public String name = "Father'name";
      
 }

 public class Son extends Father{
	public String name = "Son'name";

	public static void main(String[] args){
		Father instance = new Son();
		System.out.println(instance.name);
	}
}
運行結果:Father'name

這裏還能夠從另一個方面來講明:若是將Father類的

public String name = "Father'name";
那麼編譯器將報錯:  錯誤: name能夠在Father中訪問private  這行代碼執行時,訪問的是父類的 name屬性,而該屬性被聲明爲private,因此沒法訪問,於是報錯!

下面再分析一個例子:

class A
{
    int count = 20;
}

class B extends A
{
    int count = 200;
}

public class Test 
{
    public static void main(String[] args) 
    {
        A a = new A();
        System.out.println(a.count);
        B b = new B();
        System.out.println(b.count);
        A ab = b;   //向上轉型
        System.out.println(ab.count);
    }
}

運行結果  : 20
           200
           20

結果分析:

 前兩行的輸出毫無疑問,問題在

        A ab = b;    

        System.out.println(ab.count);

的輸出是20,而不是200;在這之間咱們能夠用

        System.out.println(ab == b);   

來進行簡單的判斷,結果輸出爲 true ,說明 ab 和 b 兩個引用變量指向同一個實例,既然 ab 和 b 指向同一個實例,爲何輸出的是20不是200呢?緣由在於:

一、對於 class A 和class B來講,class B是class A的子類,因爲子類的變量並不會覆蓋父類的變量,因此實際上在class B中是存在來兩個count,在這分別記做 A.count 和B.count ;

二、雖然在 class B中存在A.count 和B.count ,可是究竟輸出那一個 count ,取決於該引用變量的聲明時類型(本文開頭紅色文字部分已經說明),此處 聲明時類型 是 class A,因此輸出 20 即A.count ,同理若改成 B ab = b ;則輸出 200 即 B.count ;

相關文章
相關標籤/搜索