1 概念: 把引用變量轉化為子類類型,則成為向下轉型。如果把引用變量轉化為父類類型,則成為向上轉型。
Java代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1cldWYtl2Lc12bj5SZ5VGdp5ybilWYoVGavw1LcpDc0RHaiojIsJye.png)
- public class Base {
- String var = "baseVar";
- static String staticVar = "staticBaseVar";
- void method() {
- System.out.println("Base method");
- }
- static void staticMethod() {
- System.out.println("Base static Method");
- }
- }
- public class Sub extends Base {
- String var = "subVar";
- static String staticVar = "staticSubVar";
- // 覆寫父類的method()方法
- void method() {
- System.out.println("Sub static Method");
- }
- String subVar = "var only belonging to Sub";
- void subMethod() {
- System.out.println("Method only belonging to Sub");
- }
- public static void main(String args[]) {
- // who 被聲明為Base類型,引用Sub執行個體
- Base who = new Sub();
- System.out.println("who.var=" + who.var);// print:who.var=baseVar
- System.out.println("who.staticVar=" + who.staticVar);// print:who.staticVar=staticBaseVar
- who.method();// print:Sub static Metho
- // 這裡為什麼不列印Base method呢 這是java動态機制的表現,
- // 雖然who的類型是Base 但是 實際引用的是Sub類 new Sub()會在堆區配置設定記憶體空間
- // 當who.method()方法時,jvm會根據who持有的引用定位到堆區的Sub執行個體
- // 再根據Sub持有的引用 定位到方法區Sub類的類型資訊 獲得method的位元組
- // 在目前環境下(上面代碼所示)獲得method的位元組碼,此時Sub類複寫了Base的method的方法,
- // 獲得method的位元組碼,直接執行method包含的指令,
- // 如果沒有複寫method方法 則去獲得Base類的位元組碼 執行包含的指令(這個機制實作有待去研究有關資料)
- who.staticMethod();// print:Base static Method
- // who.subVar="123";//編譯錯誤
- // who.subMethod();//編譯錯誤
- // 對于一個引用變量,java編譯器按照它什麼的類型來處理,這裡who 的類型是Base類型的引用變量.不存在subVar
- // 和subMethod方法
- // 如果要通路Sub類成員,可以進行強制類型轉換(向下轉型)
- Sub sub = (Sub) who;
- sub.subVar = "23";
- sub.subMethod();
- Base base2 = new Base();
- Sub sub2 = (Sub) base2;
- sub2.subMethod();
- // 編譯通過 但是抛出ClassCastException
- // sub2實際引用的是Base執行個體
- // 對應一個引用類型的變量,運作時jvm按照它實際引用的對象來處理,假設上面能夠通過,但是
- // 當我們sub2引用變量調用subMethod()方法時,我們看到在Base類中并沒有subMethod方法。
- // 由此可見 ,子類對象可以向上轉型為父類對象,但是父類對象不能轉換為子類對象,父類擁有的成員子類
- // 子類肯定也有,而子類擁有的成員父類不一定有。上面就是一個例子。
- // 在運作時環境中,通過引用類型變量來通路所引用的方法和屬性時,java虛拟機采用如下綁定機制。
- // 1 執行個體方法與引用變量 實際引用的對象 的方法綁定 屬于動态綁定.由運作時jvm動态決定的。
- // 2 靜态方法與引用變了所聲明的對象 的方法綁定 屬于靜态綁定 在編譯階段就已經做了綁定
- // 3 成員變量 (靜态和執行個體)與引用變量所聲明的類型的成員變量綁定屬于靜态綁定。
- }
- }
Java代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1cldWYtl2Lc12bj5SZ5VGdp5ybilWYoVGavw1LcpDc0RHaiojIsJye.png)
- abstract class A {
- abstract void method();
- void test() {
- method();// 這裡調用哪個類的method方法呢
- }
- }
- public class B extends A {
- @Override
- void method() {
- System.out.println("B method");
- }
- public static void main(String[] args) {
- new B().test(); // print:B method
- // 方法test()在父類A中定義,它調用了方法method
- // 但是method在A中是抽象的 但是仍然可以調用
- // 因為在運作時環境中jvm會執行B的執行個體的method方法
- // 一個執行個體所屬的類肯定是實作了父類中所有的抽象方法
- }
- }
Java代碼
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnLyFGdz9lbvNWavw1cldWYtl2Lc12bj5SZ5VGdp5ybilWYoVGavw1LcpDc0RHaiojIsJye.png)
- class A {
- void method() {
- System.out.println("A method");
- };
- void test() {
- method();// 這裡調用哪個類的method方法呢
- }
- }
- public class B extends A {
- @Override
- void method() {
- System.out.println("B method");
- }
- public static void main(String[] args) {
- //new B().test(); // print:B method
- // 方法test()在父類A中定義,它調用了方法method
- // 但是method在A中是抽象的 但是仍然可以調用
- // 因為在運作時環境中jvm會執行B的執行個體的method方法
- // 一個執行個體所屬的類肯定是實作了父類中所有的抽象方法
- new A().test();
- new B().test();
- //test()方法在A類中定義,它調用了method()方法,和上面的例子的差別是父類A的method方法
- //不是抽象的,但是通過new B().test()執行的仍然是子類B的method方法,由此可見
- //在運作時環境中,當通過B類的執行個體去調用一系列的執行個體方法(包括一個方法調用另外一個方法)
- //将優先和B類本身包含的執行個體方法動态綁定,如果沒有這個執行個體方法,才會從父類A中繼承來的
- //執行個體方法動态綁定。
- }
- }
——————————————————————————————————————————————————————————————————————————————————————— 實驗測試:
import java.util.ArrayList;
import java.util.List;
public class BreakTest {
public static void main(String arg[]){
List<String> list = new ArrayList<String>();
list.add("a");
//編譯時類型是List,運作時類型是ArrayList,而List接口的實作類不隻有ArrayList一個,用一個List類型的引用這是“面向接口程式設計”,好處有很多
//,提但是盡量面向接口程式設計,這裡隻說一個這樣寫的好處:
//強轉 類型後, list才能調用 ArrayList()實作類的方法
((ArrayList<String>) list).ensureCapacity(16);
System.out.println("list size :" + list.size());
//Child類向上轉型,編譯時是Father類,可運作時是Child類,調用的方法自然是對子類進行調用。好處,實作面向對象的多态性
Father people = new Child();
people.eat();
Son son =new Son();
}
//内部内聲明成static
//因為Father是一個動态的内部類,建立這樣的對象必須有執行個體與之對應,程式是在靜态方法中直接調用動态内部類會報這樣錯誤
//。 如果類是單獨放在另一檔案裡,不會報錯
//這樣的錯誤好比類中的靜态方法不能直接調用動态方法。可以把該内部類聲明為static。或者不要在靜态方法中調用。
static class Father{
public void eat(){
System.out.println("father eat!");
}
}
static class Child extends Father{
public void eat(){
System.out.println("chlid eat!");
}
}
}
輸出結果:
總結: 1 概念: 把引用變量轉化為子類類型,則成為向下轉型。如果把引用變量轉化為父類類型,則成為向上轉型。 2.java繼承向上轉型和向下轉型和動态綁定 顯示的是一個目的:就是java的多态性