轉載自:https://blog.csdn.net/qq_36515344/article/details/84679082
Father father = new Son();//正確
當Son繼承於Father類時,這種情況的引用編譯器是支持的,
Son son= new Father();//錯誤
而反之卻不能。
這是由內存機制決定的,父類聲明的引用的可見區域是父類的字段和方法,而子類聲明的引用的可見區域是子類和父類中繼承下來的全部字段和方法,這就造成了父類引用訪問子類實例的時候是內存安全的,而子類引用訪問父類實例是會導致內存問題的。
我們可以使用下面一段代碼來驗證父類引用的可視性(它只能在內存中找到父類中定義了的相關字段和方法)。
//test.java
public class test{
public static void main(String[] args){
Father father = new Son();
father.run();
//System.out.println(father.son);//錯誤,對於父類引用father來說,子類實例中的son字段是不存在的
}
//father.java
public class Father{
int fa = 0;
void run(){
System.out.println("father");
}
}
//son.java
public class Son extends Father{
int son = 1;
void run(){
System.out.println("son");
}
}
輸出結果爲son(調用的是子類中的方法)
這裏爲什麼調用的是子類的方法呢?父類的引用調用了子類的方法
那對於相同名的字段而言會出現像方法一樣的情況嗎?
public class test{
public static void main(String[] args){
Father father = new Son();
System.out.println(father.fa);
father.run();
}
}
class Father{
int fa = 0;//相同字段
void run(){
System.out.println("father");
}
}
class Son extends Father{
int fa = 1;//相同字段
void run(){
System.out.println(super.fa);
System.out.println(fa);
System.out.println("son");
}
}
輸出結果:
我們發現它調用的是父類的fa字段,那這是爲什麼呢?
說明繼承對字段和方法的處理是不一樣的,對於字段而言,是不存在重寫的,如果有相同的兩個字段,是會同時存在的,但是對於父類和子類的引用而言,這兩個字段的可見性是不同的,而子類中的方法會重寫父類中的同名方法,這時候子類實例的內存空間中是存在兩個同名字段和子類重寫後的方法的引用。所以,父類引用調用的方法是子類重寫過後的方法。