JavaSE基礎知識學習-----多型

讀書遛狗遠方發表於2018-02-28

多型

Java物件導向程式設計有三大特性:封裝,繼承和多型 封裝隱藏類的內部具體實現機制,保護資料,對外界隱藏內部細節,只向外部提供它所允許訪問的方法 繼承是為了複用程式碼和實現向上轉型,當然繼承也是為多型做準備。 多型可以說是Java物件導向的精華所在。

什麼是多型

多型是指允許不同子型別的物件對同一訊息做出不同的響應,簡單來講,就是用同樣的物件呼叫同樣的方法但是卻做了不同的事情。也可以理解為一個事物的多種表現形態。 多型性分為編譯時的多型性和執行時的多型性。例如: 方法過載:實現的是編譯時的多型性 方法重寫:實現的是執行是的多型性 子類物件的多型性,這個是Java多型性中最常用的事。

實現多型的條件

1.方法重寫,也就是說要有繼承吧,只有有了繼承,子類重寫了父類已有的或抽象的方法 2.物件造型,也就是說要有父類的引用指向子類物件 只有這樣,同樣的引用呼叫同樣的方法就會作出不同的響應,簡單來講如下程式碼所示: 父類Person有如下方法:

public void walk(){
	System.out.println("人走路");
}

public void eat(){
	System.out.println("人吃飯");
}
複製程式碼

如果子類Man類沒有重寫這兩個方法,那麼我們做如下的事情:

	Person man = new Man();
    man.walk();
複製程式碼

輸出結果:

人走路
複製程式碼

綜上所述:父類引用man指向的是子類物件,這個就是子類物件的多型性(也叫向上轉型),man可以呼叫父類的方法,前提是子類沒有重寫父類方法。 如果子類Man類重寫了父類方法

public void walk(){
	System.out.println("男人應該挺拔的走路");
}

public void eat(){
	System.out.println("男人應該多吃肉");
}
複製程式碼

同樣的呼叫:

Person man = new Man();
man.walk();
複製程式碼

結果就是:

男人應該挺拔的走路
複製程式碼

綜上所述:子類物件重寫了父類方法,那麼man呼叫父類方法,執行的就是子類的方法。這個也虛擬方法呼叫,說到這裡你應該可以猜到,什麼是多型了吧,就是同樣的父類物件應用,指向不同的子類物件,就會作出不同的響應,例如子類Woman類也重寫了父類的方法:

public void walk(){
	System.out.println("女人應該溫柔的走路");
}

public void eat(){
	System.out.println("女人應該少吃肉多吃水果蔬菜");
}
複製程式碼

呼叫方法:

Person man = new Man();
Person woman = new Woman();
man.walk();
woman.walk();
複製程式碼

結果為:

男人應該挺拔的走路
女人應該溫柔的走路
複製程式碼

綜上所述:應該是很清晰了什麼是子類物件的多型性,就是你相同的父類引用,不同的子類物件,就會響應對應的子類物件的方法。

方法過載和方法重寫

方法過載和方法重寫兩者都是實現多型的方式,區別在於方法過載實現的是編譯時的多型,方法重寫實現的是執行時的多型,過載發生在同一個類中,同名的方法有不同的引數列表。

注意:方法的過載與返回值無關,簡稱兩同一不同,同一個類,同一個方法,不同的引數列表

方法的重寫發生在子類和父類之間,重寫要求子類方法返回值,方法名,引數列表與父類爆出一致,許可權修飾符大於父類,同時要同為static或同為非static。

注意:構造器不能被繼承,所以不能被重寫,但是卻可以被過載

多型的使用例子

例如在父類Person類中有如下方法:

public void show(Person person){
	System.out.println("這是父類show方法");
}
複製程式碼

子類Man類重寫了子類方法:

public void show(Person person){
	System.out.println("這是子類show方法");
}
複製程式碼

如果例項化Man物件,呼叫man的show(Person person)方法,就應該傳入Person物件,這個時候就可以傳入父類物件的引用。

Person man = new Man();
man.show(man);
複製程式碼

父類引用指向不同的子類物件,作出不同的響應。

多型經典案例

摘自http://blog.csdn.net/thinkGhoster/archive/2008/04/19/2307001.aspx

    public class A {  
    public String show(D obj) {  
        return ("A and D");  
    }  
  
    public String show(A obj) {  
        return ("A and A");  
    }   
  
}  
  
public class B extends A{  
    public String show(B obj){  
        return ("B and B");  
    }  
      
    public String show(A obj){  
        return ("B and A");  
    }   
}  
  
public class C extends B{  
  
}  
  
public class D extends B{  
  
}  
  
public class Test {  
    public static void main(String[] args) {  
        A a1 = new A();  
        A a2 = new B();  
        B b = new B();  
        C c = new C();  
        D d = new D();  
          
        System.out.println("1--" + a1.show(b));  
        System.out.println("2--" + a1.show(c));  
        System.out.println("3--" + a1.show(d));  
        System.out.println("4--" + a2.show(b));  
        System.out.println("5--" + a2.show(c));  
        System.out.println("6--" + a2.show(d));  
        System.out.println("7--" + b.show(b));  
        System.out.println("8--" + b.show(c));  
        System.out.println("9--" + b.show(d));        
    }  
}  
複製程式碼

輸出結果為:

1--A and A  
2--A and A  
3--A and D  
4--B and A  
5--B and A  
6--A and D  
7--B and B  
8--B and B  
9--A and D  
複製程式碼

結果分析如下:

System.out.println("1--" + a1.show(b)); //a1是A的引用指向是A物件,故呼叫A中的show方法,傳入的是b,b指向的是B物件,因為B繼承與A,故傳入的也可認為是A,結果為A and A
System.out.println("2--" + a1.show(c)); //c指向C物件,C繼承B,B繼承A,相當於傳入A,結果為A and A
System.out.println("3--" + a1.show(d)); //d指向D物件,在A中有傳入D物件的方法,結果為 A and D
System.out.println("4--" + a2.show(b)); //a2是父類引用,指向子類物件,按理說呼叫show方法會執行子類B的show方法,傳入的是b,b指向的是B物件,
                                        //但是B中的show(B)是子類特有的方法,故不能被呼叫,傳入的是B,B繼承與A,相當於傳入A,B類重寫了show(B)方法,結果為B and A
System.out.println("5--" + a2.show(c)); //傳入c,執行B中show(C)的方法,沒有,C繼承B,執行B中show(B),但是這是B中特有方法,不能被呼叫,
										//B繼承A,呼叫B中show(A),結果B and A
System.out.println("6--" + a2.show(d)); //傳入D,執行B中show(D)方法,沒有,但是A中有就會執行父類show(D)方法,所以結果為:A and D
System.out.println("7--" + b.show(b)); //b指向B,傳入B, 結果為B and B
System.out.println("8--" + b.show(c)); //傳入c,執行B中show(C),沒有,C繼承B,執行B中show(B),結果為:B and B
System.out.println("9--" + b.show(d)); //傳入d,執行B中show(D)方法,沒有,當時B繼承A,是存在A中show(D)的方法,結果為 A and D 
複製程式碼

案例總結

對於a2.show(c)來講,a2是A的應用,故先去A中找show(C)方法(this.show(O)),A中沒有,按理應該去A的父類中找(super.show(O)),但是A沒有父類,故只能在A中找show(c的父類)方法(this.show(super)),c的父類有B和A,A中找到show(A)的方法,但是B重寫了該方法,故執行子類的方法,所以結果為B and A。找的順序是this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

相關文章