第02組 Alpha衝刺 總結
0x01概念
多型從字面上理解,就是多種狀態的意思。在面向物件的語言中,介面的多種不同實現方式即為多型。
多型性是允許你將父物件設定成為一個或更多的他的子物件相等的技術,賦值之後,父物件就可以根據當前賦值給它的子物件的特性以不同的方式運作。
也就是說,多型是通過指向父類的指標來呼叫在不同子類中實現的方法。
多型的優點
1、消除型別之間的耦合關係
2、可替換性
3、可擴充性
4、介面性
5、靈活性
6、簡化性
0x02前提條件
繼承關係下,每一個子類都定義有一個同名的成員方法。
繼承:在多型中必須存在有繼承關係的子類和父類
重寫:子類對父類中某些方法進行重新定義,在呼叫這些方法時就會呼叫子類的方法。
向上轉型(父類引用指向子類物件):
0x03示例展示
public class Test { public static void main(String[] args) { show(new Cat()); // 以 Cat 物件呼叫 show 方法 show(new Dog()); // 以 Dog 物件呼叫 show 方法 Animal a = new Cat(); // 向上轉型 a.eat(); // 呼叫的是 Cat 的 eatCat c = (Cat)a; // 向下轉型 c.work(); // 呼叫的是 Cat 的 work } public static void show(Animal a) { a.eat(); // 型別判斷 if (a instanceof Cat) { // 貓做的事情 Cat c = (Cat)a; c.work(); } else if (a instanceof Dog) { //狗做的事情 Dog c = (Dog)a; c.work(); } } } abstract class Animal { abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("吃魚"); } public void work() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("吃骨頭"); } public void work() { System.out.println("看家"); } }
執行的結果將會輸出
吃魚
抓老鼠
吃骨頭
看家
吃魚
抓老鼠
重寫
重寫是子類對父類的允許訪問的方法的實現過程進行重新編寫,返回值和形參都不能改變。
重寫的好處在於子類可以根據需要,定義特定於自己的行為。也就是說,子類能夠根據需要實現父類的方法。
重寫方法不能丟擲新的檢查異常或者比被重寫方法申明更加寬泛的異常。
在面向物件原則裡,重寫意味著可以重寫任何現有方法,比如
class Animal{ public void move(){ System.out.println("動物可以移動"); } } class Dog extends Animal{ public void move(){ System.out.println("狗可以跑和走"); } } public class TestDog{ public static void main(String args[]){ Animal a = new Animal(); // Animal 物件 Animal b = new Dog(); // Dog 物件 a.move();// 執行 Animal 類的方法 b.move();//執行 Dog 類的方法 } }
以上編譯大的執行結果為
動物可以移動
狗可以跑和走
在上面的例子中可以看到,儘管 b 屬於 Animal 型別,但是它的執行的是 Dog 類的 move 方法。
這是由於在編譯階段,只是檢查引數的引用型別。
然而在執行時,Java虛擬機器指定物件的型別並且執行該物件的方法。
方法的重寫規則在於
引數列表與被重寫方法的引數列表必須完全相同。
返回型別與被重寫方法的返回型別可以不相同,但是必須是父類返回值的派生類(java5 及更早版本返回型別要一樣,java7 及更高版本可以不同)。
訪問許可權不能比父類中被重寫的方法的訪問許可權更低。例如:如果父類的一個方法被宣告為 public,那麼在子類中重寫該方法就不能宣告為 protected。
父類的成員方法只能被它的子類重寫。
宣告為 final 的方法不能被重寫。
宣告為 static 的方法不能被重寫,但是能夠被再次宣告。
子類和父類在同一個包中,那麼子類可以重寫父類所有方法,除了宣告為 private 和 final 的方法。
子類和父類不在同一個包中,那麼子類只能夠重寫父類的宣告為 public 和 protected 的非 final 方法。
重寫的方法能夠丟擲任何非強制異常,無論被重寫的方法是否丟擲異常。但是,重寫的方法不能丟擲新的強制性異常,或者比被重寫方法宣告的更廣泛的強制性異常,反之則可以。
構造方法不能被重寫。
如果不能繼承一個類,則不能重寫該類的方法。
介面
介面,在JAVA程式語言中是一個抽象型別,是抽象方法的集合,介面通常以interface來宣告。一個類通過繼承介面的方式,從而來繼承介面的抽象方法。
介面要包含類要實現的方法。
介面無法被例項化,但是可以被實現。一個實現介面的類,必須要實現介面內所描述的所有方法,否則就必須宣告為抽象類。例外,在 Java 中,介面型別可以來宣告一個變數,他們可以成為一個空指標,或是被繫結在一個以此介面實現的物件。
例項
/* 檔名 : MammalInt.java */ public class MammalInt implements Animal{ public void eat(){ System.out.println("Mammal eats"); } public void travel(){ System.out.println("Mammal travels"); } public int noOfLegs(){ return 0; } public static void main(String args[]){ MammalInt m = new MammalInt(); m.eat(); m.travel(); } }
執行結果為
Mammal eats
Mammal travels
抽象類
在面向物件的概念中,所有的物件都是通過類來描繪的,但是反過來,並不是所有的類都是用來描繪物件的,如果一個類中沒有包含足夠的資訊來描繪一個具體的物件,這樣的類就是抽象類。
抽象類除了不能例項化物件之外,類的其它功能依然存在,成員變數、成員方法和構造方法的訪問方式和普通類一樣。
由於抽象類不能例項化物件,所以抽象類必須被繼承,才能被使用。
例項如下
/* 檔名 : Employee.java */ public abstract class Employee { private String name; private String address; private int number; public Employee(String name, String address, int number) { System.out.println("Constructing an Employee"); this.name = name; this.address = address; this.number = number; } public double computePay() { System.out.println("Inside Employee computePay"); return 0.0; } public void mailCheck() { System.out.println("Mailing a check to " + this.name + " " + this.address); } public String toString() { return name + " " + address + " " + number; } public String getName() { return name; } public String getAddress() { return address; } public void setAddress(String newAddress) { address = newAddress; } public int getNumber() { return number; } }
多型的實現方式
方式一:重寫
方式二:介面
方式三:抽象類
(水文)