多型有一種情況是,父類應用指向子類物件:
父親 fu = new 兒子();
這個時候如果父親中有變數(包括靜態和非靜態變數)或者靜態方法,都不會被兒子覆蓋和重寫。他們在記憶體中佔用的是兩塊地方。
而非靜態方法則會被重寫。
記憶體中該物件的內容:
父類的成員變數 ①
父類的靜態方法 ①
子類的成員變數 ②
子類的靜態方法 ②
父類中未被重寫的非靜態方法 ③
父類中被子類重寫的非靜態方法 ③
子類自己新寫的方法 ④
當引用是父型別的時候指向 ① ③
當引用是子型別的時候指向 ② ③ ④
引用的型別被強制轉換的過程中記憶體中的資料都是同一組資料。
所以我們常用的方式是private 屬性 加 get set方法方式,這樣對大部分人來說不會太亂。
參考測試程式碼如下:
class Fu{
static int fu = 0;
int zi = 0;
public void me(){
System.out.println("Wo Shi Fu");
}
public static void staticMethod(){
System.out.println("Fu de static method");
}
}
class Zi extends Fu{
static int fu = 1;
int zi = 1;
public void me(){
System.out.println("Wo Shi Zi");
}
public static void staticMethod(){
System.out.println("Zi de static method");
}
}
public class Test2 {
public static void main(String[] args) {
Fu x = new Zi();
System.out.println(x.fu);
System.out.println(x.zi);
x.me();
x.staticMethod();
System.out.println("-------------華麗的分割線------------------");
//如果這個時候改變x中的變數
x.fu=99;
x.zi=99;
//強制轉換成子物件
Zi y = (Zi)x;
System.out.println("-------------強制轉換成子類型別後的內容------------------");
System.out.println(y.fu);
System.out.println(y.zi);
y.me();
y.staticMethod();
System.out.println("-------------華麗的分割線------------------");
y.fu = 88;
y.zi = 88;
System.out.println("-------------強制轉換成子類型別後----再次強制轉換為父類型別的內容------------------");
Fu a = (Fu)y;
System.out.println(a.fu);
System.out.println(a.zi);
a.me();
a.staticMethod();
System.out.println("-------------強制轉換成子類型別後----再次強制轉換為父類型別的內容------------------");
Zi b = (Zi)a;
System.out.println(b.fu);
System.out.println(b.zi);
b.me();
b.staticMethod();
}
}
輸出:
0
0
Wo Shi Zi
Fu de static method
-------------華麗的分割線------------------
-------------強制轉換成子類型別後的內容------------------
1
1
Wo Shi Zi
Zi de static method
-------------華麗的分割線------------------
-------------強制轉換成子類型別後----再次強制轉換為父類型別的內容------------------
99
99
Wo Shi Zi
Fu de static method
-------------強制轉換成子類型別後----再次強制轉換為父類型別的內容------------------
88
88
Wo Shi Zi
Zi de static method
以上僅代表個人觀點,奉勸大家盡信書不如無書,書也是人寫的。
附:
多型關於反射的擴充:
package test.test; import java.lang.reflect.Method; public class Test2 { public static void main(String[] args) throws Exception { test(new hi()); } public static void test(Object obj) throws Exception { System.out.println(obj); Object object = hi.class.newInstance(); Method mtd = hi.class.getDeclaredMethod("print", null); mtd.setAccessible(true); mtd.invoke(object, null); } } class hi{ public String toString() { return "hi"; } private void print() { System.out.println("invokeOk"); } }
輸出結果:
hi
invokeOk
呼叫test方法時,傳入引數相當於Object obj = new hi();
這個時候記憶體中是有print方法的,雖然obj沒有指向這個方法。
當用反射呼叫某個物件的某個方法時的時候,反射技術不會關心這個物件的引用有沒有指向指向這個方法,而是關心這個物件所指向的記憶體中有沒有這個方法。