首先看下面的代碼:
class Fu{
int i = 10;
}
class Zi extends Fu{
int i = 20;
}
class Test{
public static void main(String[] args)
{
Fu test = new Zi();
System.out.println(test.i);
}
}
這是一個很常規的多態,父類引用指向子類對象,引用變量所調用的方法總是表現出子類方法的行爲特徵,按照這種思想,思維慣性,上面的代碼應該輸出的是20,但是這段代碼的輸出其實是10,在這裏先給出結論:
成員變量不具備多態性,通過引用變量來訪問其包含的實例變量,系統總是試圖訪問它編譯時類型所定義的成員變量,而不是運行時類型所定義的成員變量
什麼是編譯時類型和運行時類型?
Java中的許多對象(一般都是具有父子類關係的父類對象)在運行時都會出現兩種類型:編譯時類型和運行時類型,例如:Person person
= new Student();這行代碼將會生成一個person變量,該變量的編譯時類型是Person,運行時類型是Student。
Java的引用變量有兩個類型,一個是編譯時類型,一個是運行時類型,編譯時類型由聲明該變量時使用的類型決定,運行時類型由實際賦給該變量的對象決定。如果編譯時類型和運行時類型不一致,會出現所謂的多態。因爲子類其實是一種特殊的父類,因此java允許把一個子類對象直接賦值給一個父類引用變量,無須任何類型轉換,或者被稱爲向上轉型,由系統自動完成。
依據上面的結論,在這段代碼中Fu test = new Zi();執行完後形成了多態,編譯時類型和運行時類型不一致,所以System.out.println(test.i);這一句輸出的是test編譯時類型所定義的成員變量,也就是10。