1. 程式人生 > >Java多型的經典例項分析

Java多型的經典例項分析

目錄

一、多型的表現形式

兩種

1.方法的過載和重寫

2.物件的多型性(向上轉型和向下轉型)

二、過載和重寫的簡單介紹

1.過載(overload)

        1)在同一個類中

        2)有兩個或兩個以上重名的方法

        3)但是方法的引數個數、型別、順序至少有一個不一樣

2.重寫(override)

        1)發生在繼承關係當中,子類對父類的方法進行的重新定義

        2)子類中的某些方法與父類中的某些方法,方法名,引數列表完全一致,即使方法體內部沒有改變,或者是空方法體也是重寫

三、向上轉型和向下轉型的簡單介紹

1.向上轉型

子類引用的物件轉換為父類型別稱為向上轉型。通俗地說就是是將子類物件轉為父類物件。此處父類物件可以是介面。

Father f=new Son();    //向上轉型

2.向下轉型

向下轉型是把父類物件轉為子類物件。

Animal a=new Animal();

Dog g=(Dog)a;    //向下轉型

四、在多型中方法的呼叫機制

1.不發生繼承的類呼叫方法時,呼叫哪個就用哪個,如果發生了過載,那麼,可以根據引數個數,型別,順序判斷到底呼叫了哪一個方法

2.當發生了繼承關係,但是沒有向上,向下轉型時,子類物件呼叫的方法,要麼是自身獨有的,要麼就是自身重寫的,如果沒有重寫,那麼也會直接呼叫父類的方法;而父類物件則只能呼叫自身的方法,而無法使用子類的方法。

3.如果發生了繼承,並且有向上轉型的物件,那就秉承著一個原則,即:編譯看左邊,執行看右邊。

也就是說,首先看父類中這個被呼叫的方法在哪裡,當父類中存在這個方法時,才可以呼叫,並且要繼續看子類中是否重寫了該方法,如果重寫了,就呼叫重寫後的方法。

總結:

當超類物件引用變數引用子類物件時,被引用物件的型別而不是引用變數的型別決定了呼叫誰的成員方法,但是這個被呼叫的方法必須是在超類中定義過的,也就是說被子類覆蓋的方法,但是它仍然要根據繼承鏈中方法呼叫的優先順序來確認方法,該優先順序為:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。

this.show(O)本類中是否有該方法

super.show(O)本類的父類中是否有該方法

this.show((super)O)本類中是否有引數父類的方法(即現在引數的父類型別作為引數的方法)

super.show((super)O)本類的父類中是否有引數父類的方法

五、例項的分析

package test;

class A {
	public String show(D obj) {
		return ("A and D");
	}

	public String show(A obj) {
		return ("A and A");
	}
}

class B extends A {
	public String show(B obj) {
		return ("B and B");
	}
	
	public String show(A obj) {
		return ("B and A");
	}
}

class C extends B {
}

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();
	   
	        a1.show(b);//"A and A"
	        System.out.println(a1.show(b));//A and A
	        a1.show(c);//"A and A"
	        System.out.println(a1.show(c));//a and A
	        a1.show(d);//"A and D"
	        System.out.println(a1.show(d));//A and D
		
	        a2.show(b);//"B and B"錯了
	        System.out.println(a2.show(b));//B and A
		a2.show(c);//"B and B"錯了
		System.out.println(a2.show(c));//B and A
		a2.show(d);//"A and D
		System.out.println(a2.show(d));//A and D
		
	        b.show(b);//"B and B"
	        System.out.println(b.show(b));//B and B
		b.show(c);//"B and B"	
		System.out.println(b.show(c));//B and B
		b.show(d);//"A and D"	 
		System.out.println(b.show(d));//A and D
	}

}

註釋的部分分別是我猜測的答案和真是輸出的答案。

下面分塊說明

1.繼承關係

A是B的父類,B是C和D的父類

並且C,D沒有重寫B的任何方法,也沒有自身的方法

B對A進行了方法的重寫show(A obj)

單獨看B,它的兩個show方法就屬於過載

class B extends A {
	public String show(B obj) {
		return ("B and B");
	}
	
	public String show(A obj) {
		return ("B and A");
	}
}

class C extends B {
}

class D extends B {
}

2.new物件的分析

由於呼叫方法只用到了這三個物件,因此只看這三個。

a1單純的A物件

a2發生了向上轉型,A引用B的物件

b單純的B物件

                A a1 = new A();  
	   
		A a2 = new B();  
	   
		B b = new B();

3.對於方法的呼叫

  1)a1物件呼叫,以a1.show(b)為例,首先A中並沒有show(B obj)的方法,A繼承於Object類,其中也沒有show(B obj)。

        那麼由於B繼承於A,看A中是否有show(A obj),好的,有,那麼就呼叫該方法,輸出“A and A”

                System.out.println(a1.show(b));//A and A
	        System.out.println(a1.show(c));//A and A
	        System.out.println(a1.show(d));//A and D

2)a2物件呼叫,以a2.show(b)為例,因為是向上轉型,那麼遵循,編譯看左,執行看右的原則,在父類A中沒有show(B obj)方法,但同樣的有show(A obj),因此要呼叫該方法;又因為在B中重寫了A中的show(A obj),因此在呼叫的時候就呼叫了子類重寫的show(A obj),輸出“B and A”

		
	        System.out.println(a2.show(b));//B and A
		System.out.println(a2.show(c));//B and A
		System.out.println(a2.show(d));//A and D

3)b物件呼叫,以b.show(b)為例,在B中恰好就有show(B obj)的方法,因此就輸出"B and B"

		System.out.println(b.show(b));//B and B
		System.out.println(b.show(c));//B and B 
		System.out.println(b.show(d));//A and D