面向對象
多態:
多態的概述:某一類事物的多種存在的多種形態。
1,多態的體現
父類的引用指向了自己的子類對象。
2,多態的前提父類的引用也可以接收自己的子類對象。
必須是類與類之間有關係。要麼繼承,要麼實現。
通常還有一個前提:存在覆蓋。
3,多態的好處
4,多態的弊端多態的出現大大的提高程序的擴展性。
提高了擴展性,但是隻能使用父類的引用訪問父類中的成員。
5,多態的應用
- abstractclass Animal {
- public abstractvoid eat();
- }
- class Cat extends Animal {
- public void eat(){
- System.out.println("喫魚");
- }
- public void catchMouse() {
- System.out.println("抓老鼠");
- }
- }
- class Dog extends Animal {
- public void eat() {
- System.out.println("喫骨頭");
- }
- public void kanJia() {
- System.out.println("看家");
- }
- }
- class Pig extends Animal {
- public void eat() {
- System.out.println("飼料");
- }
- public void gongDi() {
- System.out.println("拱地");
- }
- }
- class DuoTaiTest {
- public static void main(String[] args) {
- Animal a = new Cat();
- //類型提升。 向上轉型。 父類類型指向子類對象
- a.eat(); //喫魚
- //如果想要調用貓的特有方法時,如何操作?
- //強制將父類的引用。轉成子類類型。向下轉型。
- Cat c = (Cat)a;
- c.catchMouse(); //抓老鼠
- //不要出現這樣的操作,就是將父類對象轉成子類類型。
- //我們能轉換的是父類應用指向了自己的子類對象時。
- //該應用可以被提升,也可以被強制轉換。
- //多態自始至終都是子類對象在做着變化。
- // Animal a = new Animal();
- // Cat c = (Cat)a;
- /*
- 父 x = new 子();
- x.工作();
- 子 y = (子)x;
- y.玩();
- */
- function(new Cat());
- function(new Dog());
- function(new Pig());
- a instanceof animal
- }
- public static void function(Animal a){//Animal a = new Cat();
- if(!(a instanceof Animal)) {
- System.out.println("類型不匹配");
- }
- else{
- a.eat();
- if(a instanceof Cat) {
- Cat c = (Cat)a;
- c.catchMouse();
- }
- else if(a instanceof Dog) {
- Dog c = (Dog)a;
- c.kanJia();
- }
- else if (ainstanceof Pig()){
- Pig p = (Pig)a;
- a.gongDi();
- }
- }
- //instanceof : 用於判斷對象的類型。
- //對象 intanceof 類型(類類型 接口類型)
- }
- }
多態==晚綁定。
不要把函數重載理解爲多態。
因爲多態是一種運行期的行爲,不是編譯期的行爲。
多態:父類型的引用可以指向子類型的對象。
比如 Parent p = new Child();
當使用多態方式調用方法時,首先檢查父類中是否有該方法,如果沒有,則編譯錯誤;
如果有,再去調用子類的該同名方法。
(注意此處,靜態static方法屬於特殊情況,靜態方法只能繼承,不能重寫Override,如果子類中定義了同名同形式的靜態方法,它對父類方法只起到隱藏的作用。調用的時候用誰的引用,則調用誰的版本。)
(參考學習鏈接:http://docs.oracle.com/javase/tutorial/java/IandI/override.html)
如果想要調用子類中有而父類中沒有的方法,需要進行強制類型轉換,如上面的例子中,將p轉換爲子類Child類型的引用。
因爲當用父類的引用指向子類的對象,用父類引用調用方法時,找不到父類中不存在的方法。這時候需要進行向下的類型轉換,將父類引用轉換爲子類引用。
結合實例說明
下面舉個例子(有問題的代碼已註釋):
主要講講兩種類型轉換和兩種編譯時候的錯誤。
多態示例代碼
例子的執行結果:
這段代碼:
Cat類中定義了eat()方法,但是Animal類中沒有這個方法,a1引用是Animal類的,所以找不到,編譯時出錯:
兩種類型的類型轉換
(1)向上類型轉換(Upcast):將子類型轉換爲父類型。
對於向上的類型轉換,不需要顯示指定,即不需要加上前面的小括號和父類類型名。
(2)向下類型轉換(Downcast):將父類型轉換爲子類型。
對於向下的類型轉換,必須要顯式指定,即必須要使用強制類型轉換。
並且父類型的引用必須指向子類的對象,即指向誰才能轉換成誰。
不然也會編譯出錯:
因爲父類引用指向的是Cat類的對象,而要強制轉換成Dog類,這是不可能的。
多態總結:其實我們生活中有很多地方也是用到多態的,比如生活的角色扮演,是兒子的話,看到爸爸應該叫爸爸,是學生看到老師,應該叫老師,我們在身份時時刻刻在進行不斷的變化,這就是多態。
多態注意:
成員的特點:
1,成員變量。
編譯時:參考引用型變量所屬的類中的是否有調用的成員變量,有,編譯通過,沒有,編譯失敗。
運行時:參考引用型變量所屬的類中的是否有調用的成員變量,並運行該所屬類中的成員變量。
簡單總結:編譯和運行都參考等號的左邊。哦了。
2,成員函數(非靜態)。
編譯時:參考引用型變量所屬的類中的是否有調用的函數。有,編譯通過,沒有,編譯失敗。
運行時:參考的是對象所屬的類中是否有調用的函數。
簡單總結:編譯看左邊,運行看右邊。因爲成員函數存在覆蓋特性。
3,靜態函數。
編譯時:參考引用型變量所屬的類中的是否有調用的靜態方法。
運行時:參考引用型變量所屬的類中的是否有調用的靜態方法。
其實對於靜態方法,是不需要對象的。直接用類名調用即可。
簡單總結:編譯和運行都看左邊。
總結:非靜態成員函數,編譯時看左邊,運行時看右邊。其他都看左邊。