【面向對象】多態的一些理解

多態性是指在一個給定的類繼承層次結構中,同名的運動規律可在不同的類中具有不同的表現形式。

 

在JAVA中有兩種多態是指:運行時多態和編譯時多態。



關於類的多態性簡介如下:

多態(polymorphism)意爲一個名字可具有多種語義.在程序設計語言中,多態性是指”一種定義,多種實現”.例如,運算符+有多種含義,究竟執行哪種運算取決於參加運算的操作數類型:

1+2 //加法運算符

“1” + “2” //字符串連接運算,操作數是字符串

多態性是面向對象的核心特徵之一,類的多態性提供類中成員設計的靈活性和方法執行的多樣性.

1、類多態性表現

(1)方法重載

重載表現爲同一個類中方法的多態性.一個類生命多個重載方法就是爲一種功能提供多種實現.編譯時,根據方法實際參數的數據類型/個數和次序,決定究竟應該執行重載方法中的哪一個.

(2)子類重定義從父類繼承來的成員

當子類從父類繼承來的成員不適合子類時,子類不能刪除它們,但可以重定義它們,使弗雷成員適應子類的新需求.子類重定義父類成員,同名成員在父類與子類之間表現出多態性,父類對象引用父類成員,子類對象引用子類成員,不會產生衝突和混亂.

子類可重定義父類的同名成員變量,稱子類隱藏父類成員變量.子類也可以重定義父類的同名成員方法,當子類方法的參數列表與父類方法參數列表完全相同時,稱爲子類方法覆蓋(override)父類方法。覆蓋父類方法時,子類方法的訪問權限不能小於父類方法的權限。

由於Object類的equals()方法比較兩個對象的引用是否相等而不是值是否相等,因此一個類要覆蓋Object類的equals()方法,提供本類兩個對象比較相等方法.

覆蓋表現爲父類與子類之間方法的多態性.java 尋找執行方法的原則是:從對象所屬的類開始,尋找匹配的方法執行,如果當前類中沒有匹配的方法,則逐層向上依次在父類或祖先類中尋找匹配方法,直到Object類.



2、super 引用

在子類的成員方法中,可以使用代詞super引用父類成員.super引用的語法如下:

super([參數列表]) //在子類的構造方法體中,調用父類的構造方法

super.成員變量 //當子類隱藏父類成員變量時,引用父類同名成員變量

super.成員方法([參數列表]) //當子類覆蓋父類成員方法時,調用父類同名成員方法

*注意:super引用沒有單獨使用的語法


3、多態性有兩種:

1)編譯時多態性

對於多個同名方法,如果在編譯時能夠確定執行同名方法中的哪一個,則稱爲編譯時多態性.

2)運行時多態性

如果在編譯時不能確定,只能在運行時才能確定執行多個同名方法中的哪一個,則稱爲運行時多態性.


方法覆蓋表現出兩種多態性,當對象獲得本類實例時,爲編譯時多態性,否則爲運行時多態性,例如:

XXXX x1 = new XXXX(參數列表); //對象獲得本類實例,對象與其引用的實例類型一致

XXX xx1 = new XXX(參數列表);

x1.toString(); //編譯時多態性,執行XXX類的方法.

xx1.toString(); //編譯時多態性,執行XXXX類覆蓋的方法.

XXXX爲XXX的父類.

由於子類對象既是父類對象,父類對象與子類對象之間具有賦值相容性,父類對象能夠被賦值爲子類對象.例如,

XXXX x2 = new XXX(參數列表); //父類對象獲得子類實例,子類對象即是父類對象

x2.toString(); //運行時多態



x2聲明爲父類對象卻獲得子類XXX的實例,那麼x2.toString()究竟執行父類方法還是執行子類覆蓋的方法呢?

這分爲兩種情況:

取決於子類是否覆蓋父類方法.如果子類覆蓋父類方法,則執行子類方法;

如果沒有覆蓋,則執行父類方法.

在編譯時,僅僅依據對象所屬的類,系統無法確定到底應該執行那個類的方法,只有運行時才能確定,因此這是運行時多態.

父類對象並不能執行所有的子類方法,只能執行那些父類中聲明/子類覆蓋的子類方法.

 

 

關於java的多態,有的書上是這樣講的,它講java的多態分成靜態的多態,和動態的多態,而所謂靜態的多態就是隻函數的重載,動態的多態就是方法的覆寫。
如下面:
class Test
{
void print()
{
System.out.println("hello world");
}
void print(int x)
{
System.out.println("hello world"+i);
}
public static void main(String []args)
{
Test ts=new Test();
ts.print();
ts.print(10);
}
}
/*
上面的程序就是在一個類中成員方法的重載例子。也就是一個靜態的多態性。系統會在你編譯的時候根據你調用的方法的參數列表來動態的決定調用那一個函數。
*/

動態的多態:

class Test
{
void print()
{
System.out.println("hello Test");
}
public static void main(String []args)
{
A a=new A();
a.print();
}
}

class A extends Test
{
void print()
{
System.out.println("hello A");
}
}

/*
這時由於子類覆寫了父類的方法,所以調用的是子類覆寫後的方法。
這是動態的多態。
*/

是把一個子類的實例賦值給一個父類的問題,請看下面的程序:
class A
{
void print(){}
public static void main(String []args)
{
A [] a=new A[3];
a[0]=new B();
a[1]=new C();
a[2]=new D();
for(int i=0;i<a.length;i++)
{
a[i].print();
}
}
}

class B extends A
{
void print()
{
System.out.println("hello B");
}
}

class C extends A
{
void print()
{
System.out.println("hello C");
}
}

class D extends A
{
void print()
{
System.out.println("hello D");
}
}

/*
上面的程序執行的結果:
hello B
hello C
hello D

可以看出,程序不會調用父類的print()方法,再說父類print()方法根本什麼也不做。這就是JVM (java虛擬機),能在程序運行時,動態的識別變量的類型。就像上面一樣。這主要是考java的運行時的類型識別機制實現的,當然我認爲這其實也可以看成是java多態的一種表現。
*/

在java中子類是父類的實例,這就像是說 魚是動物。但不能說動物就一定是魚,這也是符合了人們對現實世界的認識規律。另外java爲我們提供了一個關鍵字,在孫鑫的教程裏面也講到了吧。它是instanceof
你可以用這來判斷一個對象是否是一個類的實例。還是上面的A ,B,C ,D類的例子:
在mian函數中寫上下面的代碼:(把原來的代碼刪掉)
B b=new B();
if(b instanceof A)
System.out.println("b instanceof A");
//輸出:b instanceof A

說明b是A類的實例。

再看下面的例子。
A a=new B();
if(a instanceof B)
System.out.println("a instanceof B");

//輸出:a instanceof B
但此時不能這樣,B b=a;
雖然a是B的實例但是這裏不能這樣賦值,要像下面:
B b=(B)a;
//進行類型的強制轉換

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章