1. 程式人生 > >面向物件-多型

面向物件-多型

JavaSE學習筆記第九天-面向物件之多型

  • 多型是什麼?

    • 同樣使用的是父類的引用,呼叫同一個名稱的方法,卻可以得到不同的呼叫結果,這就是Java中的多型。
    • 即:同一個函式,多種形態。
    • 實際上多型包括動態多型和靜態多型。
    • 使用多型便於靈活的拓展我們開發的程式。
  • 方法覆蓋:

    • 在類的繼承體系結構中,如果子類中出現了與父類中有同原型的方法,那麼認為子類中的方法覆蓋了父類中的方法(也稱為方法重寫)。
    • 通過子類的例項呼叫被覆蓋的方法時,將總是呼叫子類的方法,而父類的方法將被隱藏。
  • 區分方法覆蓋(重寫)和方法過載:

    • 方法重寫一般在父子類中發生,方法過載一般是同一個類中。
    • 方法重寫是方法名一致,形參型別一致,個數一致,返回值型別一致,而且許可權修飾符的許可權只能大於或等於父類的方法的許可權。
    • 可以在方法前面加上@Override檢測是否構成重寫。
    • 方法過載是方法名一樣,形參型別不一樣,返回值型別無影響,許可權修飾符也無影響。
    • 方法重寫出現的前提是必須要有繼承關係發生的情況下。
    • 方法過載時,繼承不是必須的。
    • 方法重寫要求父類和子類中的方法必須是同原型,方法過載各方法的原型是不同的。
  • 例如

    class Person{
        public void run(){
            System.out.println("人跑步!!!");
        }
    }
    
    class Student extends Person{
        public void run(){
            System.out.println("學生跑步!!!");
        }
        public void study(){
            System.out.prinln("學生學習!!!");
        }
    }
    
    class Teacher extends Person{
        public void run(){
            System.out.println("老師跑步!!!");
        }
    }
    
    class TestDemo{
        public static void main(String[] args){
            Person p = new Student();	//引用轉型
            p.run();					//呼叫學生的方法,列印學生跑步!!!
            Person p2 = new Teacher();
            p2.run();					//呼叫老師的方法,列印老師跑步!!!
            //p 和 p2都是Person類,但是同樣呼叫run方法,列印的結果卻是不一樣,我們稱這樣的就是多型
            //只有執行時候才知道執行哪個方法
            //在eclipse中,按住Ctrl鍵,點p.run();這裡會跳轉到Person的run方法,而不是執行的那個run方法,這就是動態多型。(繼承是前提!!!)
            //由上面的結果可以看出,父類引用指向子類物件,呼叫方法時,呼叫的是子類的重寫後的方法。
            //p是無法呼叫student的study方法,那麼,我們要怎麼呼叫子類特有的方法呢?
            Student st = (Student)p;	//類比強制型別轉換,上面的子類賦值給父類,就相當與自動轉換
            st.study();	//列印學生學習!!!
            //注意這裡會出現問題,因為如果把p強制轉換成Teacher物件的話,會報ClassCastException:造型異常
            //所以建議強制型別轉換是,使用instanceOf進行判斷
            if(p2 instanceOf Teacher){
                Teacher t = (Teacher)p2;
            }
        }
        
    }
    
    

    由上可以看出:如果不強制轉換成子類,那就只能呼叫父類中定義的方法,如果這個方法被子類覆蓋了,那就執行子類中的方法,如果沒有,那就呼叫父類中的方法。

    如果強制轉換了,那就可以呼叫子類中特有的一些方法,如上面的Student的study方法。

  • 靜態多型和動態多型:

    • 靜態多型:
      • 靜態多型也稱為編譯時多型,即在編譯時決定呼叫哪個方法;
      • 靜態多型一般指方法過載;
      • 只要構成了方法過載,就可以認為形成了靜態多型的條件,靜態多型與是否發生了繼承沒有必然的聯絡。
      • 靜態多型在eclipse中,按住Ctrl鍵,點選呼叫的方法會跳轉到執行的方法。
    • 動態多型:
      • 動態多型只有在執行時才知道執行哪個方法。
      • 繼承是動態多型的前提!!!
      • 子類要重寫方法。
      • 動態多型在eclipse中,按住Ctrl鍵,點選呼叫的方法,會跳轉到父類的方法,而不是執行的子類中的方法。
  • 抽象類 abstract

    • 使用abstract修飾的類就叫抽象類

    • 如果某個類中包含了抽象方法,那麼該類就必須定義為抽象類。

    • 抽象類中可以有成員變數,成員方法,靜態變數,靜態方法,構造方法,抽象方法可有可無。

    • 抽象類只能用於繼承,而且繼承的子類要實現父類的所有抽象方法,如果沒有實現所有的抽象方法,這個類也為抽象類,只能用於繼承,不能直接呼叫構造方法得到其例項。

    • 抽象方法必須為public或者protected,或者預設包許可權(因為如果為private,則不能被子類繼承,子類便無法實現該方法),預設情況下預設為包許可權;

    • 定義:

      許可權修飾符 abstract class 類名{
      	
          許可權修飾符 abstract 返回值型別 抽象方法名;
      }
      

      final和abstract,private和abstract,static和abstract,這些是不能放在一起的修飾符

      解釋:因為abstract修飾的方法是必須在其子類中實現(重寫),才能以多型方式呼叫,以上修飾符在修飾方法時期子類都重寫不了這個方法,final是不可以重寫,private是不能夠繼承到子類,所以也就不能重寫,static是可以重寫的,但是由物件的建立方式,static修飾的是優先於物件建立載入進記憶體,如果static和abstract一起用的話,子類實現了,但是先要建立父類(有父才有子),所以先載入父類,這時子類還沒有建立,當然會出問題。

  • 介面 interface

    • 使用interface定義的就是介面,沒有class關鍵字。

    • 如果某個類中的所有方法都是抽象方法,那麼可以考慮將該類定義為介面。

    • 介面比抽象類更抽象,相當於定義了一套規範和標準。

    • 介面不能被直接例項化,只能被介面繼承(extends)或被類實現(implements)。

    • 介面中只允許有常量和抽象方法。

      • 常量, public static final 常量型別 常量名 = 常量值;
      • public static final 可以省略,編譯的時候jvm會自動新增。
      • 抽象方法,所有許可權都是public ,不寫的話,預設是public ,可以省略abstract關鍵字。
    • 實現介面時,如果不實現所有的抽象方法,那就要把這個類定義為抽象類。

    • 類實現介面用implements關鍵字後面加 介面名1,介面名2,介面名3.

    • 定義:

      interface USB{
      	public void test1();
      	void test2();
      	int A = 10;
      	public static final int B = 10;
      }
      
      interface USB2 extends USB{
      	
      }
      
      abstract class Keyboard1 implements USB2{
      	public void test2() {
      		
      	}
      }
      
      class Mouse implements USB2{
      	public void test1() {
      	}
      	public void test2() {
      	}
      	
      }
      
  • 抽象類和介面的區別

    • 抽象類中可以有抽象方法,也可以沒有抽象方法(抽象方法用於約束子類的行為),抽象類中可以包含成員屬性和普通方法。一個類中如果包含抽象方法,則這個類必須定義為抽象類,一個類繼承抽象類,要麼實現所有抽象方法,要麼也是抽象類。抽象類有構造方法,但是不能被直接例項化,之能用於子類呼叫,抽象類必須被繼承。抽象類的抽象方法不寫許可權修飾符預設為包許可權。
    • 介面中只有常量和抽象方法,不能包含其他的。一個類不能繼承多個抽象類,但是可以給同時實現多個介面。藉助介面可以實現多繼承的效果。介面中的所有東西都是public訪問許可權。