Java 只有值傳遞。傳遞物件時,傳的是引用的副本(指向同一堆內存對象)。引用變量可指向子類實例,但編譯期類型決定可訪問成員。
package test;
public class FatherClass { protected int i = 0; }
public class Child extends FatherClass {
public int i1 = 1;
public void function() { System.out.println("call Child function"); }
public static void main(String[] args) throws Exception {
// 1. 父類引用指向子類實例
FatherClass f = new Child();
// f.function(); // 編譯錯誤:FatherClass 無此方法
System.out.println(f.getClass()); // class test.Child
// 2. 向下轉型:子類引用指向同一實例
Child c1 = (Child) f;
c1.function(); // 正常調用
System.out.println(c1.getClass()); // class test.Child
// 3. 反射繞過編譯期檢查
Method m = Child.class.getMethod("function");
m.invoke(f); // 正常輸出(運行時類型為 Child)
// 4. 危險:子類引用指向父類實例
Child c2 = (Child) new FatherClass(); // 編譯通過,運行拋 ClassCastException
m.invoke(c2); // 異常
}
}
the entrance. ---------------- test.Child@2a139a55 class test.Child ---------------- call Child function test.Child@2a139a55 class test.Child call Child function Exception in thread "main" java.lang.ClassCastException: test.FatherClass cannot be cast to test.Child
FatherClass f = new Child(),引用類型是 FatherClass,實例類型是 Child。f.function() 編譯失敗)。invoke 亦同)。(Child) new FatherClass() 編譯不報錯,運行必崩——父類實例不是子類。if (obj instanceof Child)。棧 (Stack) 堆 f ──────────────────────► Child 實例 (含 i=0, i1=1) c1 ──────────────────────► 同一 Child 實例 c2 ──────────────────────► FatherClass 實例 (僅 i=0) ← 類型不匹配,轉型失敗
搞清「引用」與「實例」的關係,是避免 ClassCastException、正確使用多態的關鍵。