面向物件-多型
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訪問許可權。