JAVA-入門 多態(郝斌)(整理筆記)

多態

  • 一個父類的引用類型變量它既可以指向父類對象也可以指向子類對象,它可以根據當前時刻指向的不同,自動調用不同對象的方法,這就是多態
class A
{
    public void f()
    {
        System.out.printf("AAAA\n");

    }

}
class B extends A
{
    public void f()
    {
        System.out.printf("BBBB\n");

    }

}

public class M
{
    public static void main(String[] args)
    {
        A aa = new A();
        B bb = new B();

        aa.f();
        bb.f();

        aa = bb;//OK  把bb當作aa來看待,即B轉換成A
        bb = aa; //error  把aa當作bb來看待,即A轉換成B

        /** aa代表的是父類,是一般的,可以比喻成動物
            bb代表的是子類,是具體的,可以比喻成狗

            故bb可以看作動物來對待,因爲狗是動物的一個實例

            但是動物不可以當作狗來對待,因爲還有其他動物 */


    }
}

程序運行示例:
  ——————————————————————————————————
  M.java:31: 錯誤: 不兼容的類型: A無法轉換爲B
        bb = aa;
             ^
1 個錯誤
  ——————————————————————————————————
class A
{
    public void f()
    {
        System.out.printf("AAAA\n");
    }
}
class B extends A
{
    public void f()
    {
        System.out.printf("BBBB\n");
    }
}
public class M
{
    public static void main(String[] args)
    {
        A aa = new A();
        B bb = new B();
        aa.f();		//***
        bb.f();

        aa = bb;
        aa.f();		//***

        //這就是多態! 同樣的代碼做不同的事情


    }
}

程序運行示例:
  ——————————————————————————————————
AAAA
BBBB
BBBB
  ——————————————————————————————————
class A
{
    public void f()
    {
        System.out.printf("AAAA\n");

    }

}
class B extends A
{
    public void f()
    {
        System.out.printf("BBBB\n");

    }

}

public class M
{
    public static void main(String[] args)
    {
        A aa = new B();
        aa.f();		//***
        aa = new A();
        aa.f();		//***

        //這就是多態! 同樣的代碼做不同的事情


    }
}

程序運行示例:
  ——————————————————————————————————
BBBB
AAAA
  ——————————————————————————————————
  • aa可以根據它自己當前時刻指向的是A類對象還是A子類對象,而自動決定調用哪個對象的f方法,這就是多態

多態的優點

  • 利用多態可以實現:
    • 同一段代碼做不同的事情
  • 如:
    • 假設A派生出B,B派生出C
    • 試着編寫一個函數實現調用整個A類族所有對象f方法
    • 所謂A類族就是A類及其A的子孫類所形成的一個族羣
class A
{
    public void f()
    {
        System.out.printf("AAAA\n");

    }

}
class B extends A
{
    public void f()
    {
        System.out.printf("BBBB\n");

    }

}
class C extends B
{
    public void f()
    {
        System.out.printf("CCCC\n");
    }
}

public class M
{
    public static void g(A aa)
    {
        aa.f();
    }
    public static void main(String[] args)
    {
        A aa = new A();
        B bb = new B();
        C cc = new C();

        g(aa);
        g(bb);
        g(cc);

        //這就是多態! 同樣的代碼做不同的事情
				//向後兼容

    }
}

程序運行示例:
  ——————————————————————————————————
AAAA
BBBB
CCCC
  ——————————————————————————————————
class A
{
    public void f()
    {
        System.out.printf("AAAA\n");
    }

}
class B extends A
{
        public void f()
    {
        System.out.printf("BBBB\n");
    }
    

}

public class M
{
    public static void main(String[] args)
    {
        A aa = new A();
        B bb = new B();

        // aa = bb;
				aa = (A)bb;	//單獨此行代碼不會影響bb的本身類型,這條語句本身是錯誤的
      	
      	//aa.f();
      	//bb.f();
    }
}

程序運行示例:
  ——————————————————————————————————
Exception in thread "main" java.lang.ClassCastException: class A cannot be cast to class B (A and B are in unnamed module of loader 'app')
        at M.main(M.java:28)
  ——————————————————————————————————
  
  
  程序運行示例:(三條註釋語句取消後,且刪除27行)
  ——————————————————————————————————
BBBB
  ——————————————————————————————————
class A
{
    public void f()
    {
        System.out.printf("AAAA\n");
    }

}
class B extends A
{
    public void f()
    {
        System.out.printf("BBBB\n");
    }
    public void g()
    {
        System.out.printf("GGGG\n");
    }

    

}

public class M
{
    public static void main(String[] args)
    {
        A aa = new A();
        B bb = new B();

        aa = bb;

        aa.f(); //OK 此時父類aa在調用子類的重寫函數
        aa.g(); //error 此時父類aa在調用子類的特有函數		//*********
    }
}

程序運行示例:
  ——————————————————————————————————
M.java:34: 錯誤: 找不到符號
        aa.g(); //error 此時父類aa在調用子類的特有函數
          ^
  符號:   方法 g()
  位置: 類型爲A的變量 aa
1 個錯誤
  ——————————————————————————————————

多態注意事項(難點)

  • 子類對象可以直接賦給父類對象使用,但父類對象在任何情況下都不可以直接賦給子類引用,因爲子類是父類的一種,但父類不是子類的一種,或者講子類可以當做父類看待,但父類不可以當做子類看待,“狗可以當做動物看待,但動物不可以當做狗來看待”
  • 通過父類引用只能訪問子類對象從父類繼承過來的成員

  • 通過父類引用不能訪問子類對象所特有的成員
  • 父類引用永遠不可能直接賦給子類引用
    • 只有在父類引用本身指向的就是一個子類的對象時,纔可以把父類引用強制轉換成子類引用
    • 其他情況下不允許把父類引用強制轉化爲子類引用,否則運行時會出錯
class A
{

}
class B extends A
{

}
public class M
{
    public static void main(String[] args)
    {
        A aa = new A();
        B bb = new B();

        bb = (B)aa;  //16行 編譯沒有錯誤,但運行時出錯! 因爲aa指向的是父類的對象
        A aa2 = new B();
        bb = (B)aa2;  //OK 因爲aa2本身指向的就是一個B類對象,
                        // 所以可以進行強制轉化,注意與16行的區別,在Java中絕不可能直接把父類引用賦給子類引用的
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章