自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入解析Java的多態(tài)性及應(yīng)用研究

開發(fā) 后端
多態(tài)性是面向?qū)ο蟮闹匾匦灾弧@枚嘈涡缘母拍?,可改善程序代碼的組織以及可讀性,還能創(chuàng)建“易于擴展”的程序。通過深入研究Java多態(tài)性的實現(xiàn)原理,解析具體實例,演示了多態(tài)性在程序設(shè)計中的應(yīng)用。

摘要:多態(tài)性是面向?qū)ο蟮闹匾匦灾?。利用多形性的概念,可改善程序代碼的組織以及可讀性,還能創(chuàng)建“易于擴展”的程序。通過深入研究Java多態(tài)性的實現(xiàn)原理,解析具體實例,演示了多態(tài)性在程序設(shè)計中的應(yīng)用。

關(guān)鍵詞:多態(tài);繼承;方法;抽象類;接口

中圖分類號:TP391文獻標(biāo)識碼:A文章編號:1009-3044(2007)16-31069-02

Thoroughly Analyzes Java the Polymorphism Properties and the Applied Research

ZHANG Ke-jun

(Graduate Student Third RowMilitary Economical Institute,Wuhan 430035,Chnia)

Abstract:The polymorphism properties are one of object-oriented important characteristics. Using the polymorphic concept, may improve the procedure code the organization as well as the readability, but also can found "is easy to expand" the procedure. Through in-depth study of polymorphism Java Principle, analytic specific examples, the presentation of polymorphism in the process of the application.

Key words:polymorphism;Inherits;method;abstract class;connection

“polymorphism(多態(tài))”一詞來自希臘語,意為“多種形式”。多態(tài)在面向?qū)ο笳Z言中是個很普遍的概念,同時也是對象開發(fā)軟件的一個特殊特性,指的是一個程序中同名的不同方法共存的情況。Java語言支持兩種類型的多態(tài)性:運行時的多態(tài)性和編譯時的多態(tài)性。運行時的特性(動態(tài)多態(tài)性)是指Java中的動態(tài)多態(tài)性實現(xiàn)手段---覆蓋(替換)基類中的同名成員函數(shù)(函數(shù)原型一致),其調(diào)用規(guī)則是依據(jù)對象在實例化時而非定義時的類型相應(yīng)地調(diào)用對應(yīng)類中的同名成員函數(shù)。編譯時的特性(靜態(tài)多態(tài)性)是指Java中的靜態(tài)多態(tài)性實現(xiàn)手段-----重載函數(shù),其調(diào)用規(guī)則是依據(jù)對象在定義時的類型相應(yīng)地調(diào)用對應(yīng)類中的重載函數(shù)。Java多態(tài)性的主要表現(xiàn)形式有:繼承多態(tài)、抽象多態(tài)和接口多態(tài)。

1 繼承實現(xiàn)的多態(tài)

在Java中,當(dāng)一個類獲取另一個類中所有非私有的數(shù)據(jù)和操作的定義作為自己的部分或全部成分時,就稱這兩個類之間具有「繼承」關(guān)系。「繼承」可分為「介面繼承」和「實作繼承」兩類,「介面繼承」就是只繼承父類別的函數(shù)名稱,然后子類別一定會實作取代之。所以當(dāng)我們以父類別的指標(biāo)「多型」于各子類別時,由于子類別一定會實作父類別的多型函數(shù),所以每個子類別的實作都不一樣,此時我們(使用父類別指標(biāo)的人)并不知道此多型函數(shù)到底怎么完成,因之稱為「黑箱設(shè)計」。而「實作繼承」就是繼承父類別的函數(shù)名稱,子類別在實作時,也會用到父類別的函數(shù)實作。所以我們(使用父類別指標(biāo)的人)知道此多型函數(shù)怎么完成工作,因為大概也跟父類別的函數(shù)實作差不多,因之稱為「白箱設(shè)計」。

Java的類別繼承為實作繼承,子類別會用到父類別的實作(更正確地說應(yīng)該是父類別有定義實作,所以子類別可能會使用到,即使不使用到也會遵循父類別實作的演算法),所以父類別與子類別有一定程度的相關(guān)性;Java的interface接口則是介面繼承,因為接口只能定義函數(shù)名稱,無法定義函數(shù)實作,所以子類別必須用「implements」關(guān)鍵字來實現(xiàn)繼承,且每個繼承同一介面的子類別當(dāng)然彼此不知道對方如何實作,因此為一個黑箱設(shè)計。

1.1方法的覆蓋

根據(jù)實作繼承及動態(tài)多態(tài)性的特點,派生類(子類)將繼承基類(父類)所有的方法、屬性和事件。同時,我們可根據(jù)需要來重新定義基類的方法、屬性和事件,甚至增加或者修改部分內(nèi)容,以提供不同形式的實現(xiàn)。

代碼示例一:

 

  1. //定義父類superc   
  2.   import java.io.*;   
  3.   class superc   
  4.   {public void sc()   
  5.     { System.out.println("This is superc!");   
  6.    }}   
  7.   //定義子類subc1   
  8.   class subc1 extends superc   
  9.   {public void sc()   
  10.    { System.out.println("This is subc1!!");   
  11.    }}   
  12.   //定義子類subc2   
  13.   class subc2 extends superc   
  14.   { public void sc()   
  15.    { System.out.println("This is subc2!!");   
  16.    }}   
  17.   class Test   
  18.   {public static void main(String[] arg)   
  19.   {superc a;   
  20.   subc1 b=new subc1();   
  21.   subc2 c=new subc2();   
  22.   a=b;   
  23.   a.sc();   
  24.   a=c;   
  25.   a.sc();   
  26.   }}   

 

程序運行結(jié)果為:

如上例所示,在父類superc中我們定義了方法SC(),其每一個子類都將繼承這個方法。但是,這個方法在每個子類中的具體實現(xiàn)是各不相同的。

那么,Java編譯器如何實現(xiàn)對同名方法函數(shù)的調(diào)用呢?面向?qū)ο蟪绦蜷_發(fā)中,我們將一個方法調(diào)用同一個方法主體連接到一起稱為“綁定”(Binding)。Java中綁定的所有方法都采用后期綁定技術(shù),即動態(tài)綁定:它意味著綁定在運行期間進行,以對象的類型為基礎(chǔ)。若一種語言實現(xiàn)了后期綁定,同時必須提供一些機制,可在運行期間判斷對象的類型,并分別調(diào)用適當(dāng)?shù)姆椒?。也就是說,編譯器此時依然不知道對象的類型,但方法調(diào)用機制能自己去調(diào)查,找到正確的方法主體。不同的語言對后期綁定的實現(xiàn)方法是有所區(qū)別的。但我們至少可以這樣認為:它們都要在對象中安插某些特殊類型的信息,并可通過這些區(qū)別信息實現(xiàn)多態(tài)。由于動態(tài)綁定技術(shù)的支持,Java的程序在執(zhí)行時靈活性就大大提高了。Java 的這種機制遵循如下原則:其一,當(dāng)超類(父類)對象引用變量引用子類對象時,被引用對象的類型而不是引用變量的類型決定了調(diào)用誰的成員方法,但是這個被調(diào)用的方法必須是在超類(父類)中定義過的,也就是說被子類覆蓋的方法。其二,每一個實例對象都自帶一個虛擬函數(shù)表(virtualtable),這個表中存儲的是指向虛函數(shù)的指針,實例對象通過這個表來調(diào)用虛函數(shù),以實現(xiàn)多態(tài)。實際上,使用虛擬函數(shù)表的方法,表項在編譯時便已固定,把函數(shù)映射為在虛擬函數(shù)表中的偏移,到了運行時,只知道“偏移、執(zhí)行”,至于究竟是哪個函數(shù),無從知曉。類似于查表的過程,在編譯的時候一定是存在的,但不存在于運行時。對程序而言,從源碼到運行是一個完整的過程,一些功能被某些語言放到了編譯時,而在另一些語言中被放到了運行時,折衷的原則取決于語言設(shè)計。虛擬函數(shù)表的實現(xiàn)中,每個類的表中,不僅僅要保持自己的定義的方法,還要保持自己超類的方法。我們知道,在面向?qū)ο蟮恼Z言中,子類對象常常要當(dāng)作超類對象使用,而在運行時,要找某個方法,只知“偏移”,所以,子類的虛擬函數(shù)表必須完全兼容超類的虛擬函數(shù)表,才能保證整個系統(tǒng)的正常運行,而保證的方法就是保存超類的所有表項。這樣帶來的問題是,當(dāng)子類增多,虛擬函數(shù)表就無可避免的會增多,即便子類只有一個屬于自己的方法,但它仍要帶有超類所有的方法,這是一個巨大的負擔(dān)。所以,那些建議“不要定義太龐雜的繼承系統(tǒng)”的說法,是有一定物理基礎(chǔ)的。

1.2函數(shù)的重載

重載是同一類中定義同名方法的情況。這些方法同名的原因,是它們的最終功能和目的都相同,但是由于在完成同一功能時,可能遇到不同的具體情況,所以需要定義含不同的具體內(nèi)容的方法,來代表多種具體實現(xiàn)形式。

Java支持用戶定義的函數(shù)重載。一個類中可以有相同名字的方法,這些方法可以有不同的意義。但是,這些重載的方法中,必須滿足參數(shù)數(shù)目不同,相同位置上的參數(shù)類型不同等等。這些不同可以幫助編譯器區(qū)分不同版本的方法;根據(jù)靜態(tài)多態(tài)性調(diào)用規(guī)則,編譯器依據(jù)對象在定義時的類型相應(yīng)地調(diào)用對應(yīng)類中的重載函數(shù)。

構(gòu)造函數(shù)的多態(tài)性就是典型函數(shù)重載情況。

代碼示例二:

 

  1.  import java.io.*;   
  2.   class Gz   
  3.   {//第一種構(gòu)造函數(shù)   
  4.   publicGz(){System.out.println("這個構(gòu)造函數(shù)的參數(shù)是:空");   
  5.     }   
  6.   publicGz(int s)   
  7.   {//第二種構(gòu)造函數(shù)   
  8.   System.out.println("這個構(gòu)造函數(shù)的參數(shù)是:整數(shù)");   
  9.   }   
  10.   publicGz(char m)   
  11.   {//第三種構(gòu)造函數(shù)   
  12.   System.out.println("這個構(gòu)造函數(shù)的參數(shù)是:字符型");   
  13.   }   
  14.   public static void main(String args[])   
  15.   {//三個Gz類的對象實例   
  16.   Gz aa=new Gz();   
  17.   Gz bb=new Gz(2);   
  18.   Gz cc=new Gz('a');   
  19.   }}   

 

運行結(jié)果:

上面的例子中,我們定義了若干個構(gòu)造函數(shù)Gz(),當(dāng)用戶創(chuàng)建該類對象的語句時,編譯器會自動根據(jù)給出的實際參數(shù)的數(shù)目、類型和順序來確定調(diào)用哪個構(gòu)造函數(shù)來完成對新對象的初始化工作。

同樣地,子類也可以根據(jù)實際情況對其父類的構(gòu)造函數(shù)進行覆蓋,有異曲同工的效果。但應(yīng)注意:子類如果有多個構(gòu)造函數(shù)的時候,父類要么沒有構(gòu)造成函數(shù),讓編譯器自動產(chǎn)生,那么在執(zhí)行子類構(gòu)造函數(shù)之前先執(zhí)行編譯器自動產(chǎn)生的父類缺省的構(gòu)造函數(shù);要么至少要有一個顯式的缺省構(gòu)造函數(shù)可以讓子類的構(gòu)造函數(shù)調(diào)用。

2 抽象類實現(xiàn)的多態(tài)

在很多Java程序應(yīng)用中,類層次的頂層類并不具備下層類的一些功能和方法。我們可以在超類中將這些方法聲明為沒有實現(xiàn)的抽象方法,如果一個類里包含了一個或多個抽象方法,類就必須指定成abstract即「抽象類」。使用abstract類型修飾符的抽象方法,屬于一種不完整的方法,只含有一個聲明,沒有方法主體,基類不能實現(xiàn)它,必須由派生類過載實現(xiàn),為其它子孫類用抽象機制實現(xiàn)多態(tài)性提供了統(tǒng)一的界面。對所有與基礎(chǔ)類聲明的簽名相符的衍生類方法,都可以通過上面介紹過的動態(tài)綁定機制進行調(diào)用,該類未實現(xiàn)的方法由派生類提供,已實現(xiàn)的成員仍可被重寫,并且派生類仍可以是抽象類或?qū)崿F(xiàn)附加接口等功能。

代碼示例三:

 

  1. import java.util.*;   
  2.   abstract class Animal {   
  3.   //int i; // storage allocated for each   
  4.   public abstract void Breath();   
  5.   public String what() { return "Animal";}   
  6.   public abstract void adjust();}   
  7.   class Human extends Animal {   
  8.   public void Breath() { System.out.println("Human is breathing.");}   
  9.   public String what() { return "Human"; }   
  10.   public void adjust() {}}   
  11.   class Dog extends Animal {   
  12.   public void Breath() { System.out.println("Dog is breathing.");}   
  13.   public String what() { return "Dog"; }   
  14.   public void adjust() {}}   
  15.   class Bird extends Animal {   
  16.   public void Breath() { System.out.println("Bird is breathing.");}   
  17.   public String what() { return "Bird"; }   
  18.   public void adjust() {}}   
  19.   class Woman extends Human {   
  20.   public void Breath() { System.out.println("Woman is breathing.");}   
  21.   public void adjust() { System.out.println("I am woman.");}}   
  22.   class Man extends Human {   
  23.   public void play() { System.out.println("Man is breathing.");}   
  24.     public String what() { return "Man"; }}   
  25.   public class cxhs {// Doesn't care about type, so new types   
  26.   // added to the system still work right:   
  27.   static void tune(Animal i) {// ...   
  28.   i.Breath();}   
  29.   static void tuneAll(Animal[] e) {   
  30.   for(int i = 0; i < e.length; i++)   
  31.   tune(e[i]); }   
  32.   public static void main(String[] args) {   
  33.   Animal[] orchestra = new Animal[5];   
  34.   int i = 0;   
  35.   // Upcasting during addition to the array:   
  36.   orchestra[i++] = new Human();   
  37.   orchestra[i++] = new Dog();   
  38.   orchestra[i++] = new Bird();   
  39.   orchestra[i++] = new Woman();   
  40.   orchestra[i++] = new Man();   
  41.   tuneAll(orchestra); }}   

 

運行結(jié)果:

其邏輯結(jié)構(gòu)如下圖:

由于抽象類是其所有子類的公共屬性和方法的集合,它可以在類的某些屬性和方法中提供不變的因素和功能,同時大大提高了類的其他過程的靈活性。從上面的例子可以看出,除基礎(chǔ)類以外,實際并沒有進行什么改變。創(chuàng)建抽象類和方法有時對我們非常有用,因為它們使一個類的抽象變成明顯的事實,可明確告訴用戶和編譯器自己打算如何用它。

3 接口實現(xiàn)的多態(tài)

以上所談到的多態(tài)行為均用到了類的繼承關(guān)系所建立起來的子類型關(guān)系。Java接口同樣支持用戶定義的類型,可以實現(xiàn)類型的「界面繼承」;并且Java的接口機制啟動了建立在類型層次結(jié)構(gòu)上的多態(tài)行為,能夠?qū)崿F(xiàn)接口的組合和擴充,一定程度上對Java類型及其功能進行了優(yōu)化。Java中一個類只能有一個父類,但是單個類可以實現(xiàn)一個或多個接口,多個類可實現(xiàn)相同的“接口”。

“interface”(接口)關(guān)鍵字使接口的抽象概念更深入了一層,我們可將其想象為一個“純”抽象類。接口常常被用來為具有相似功能的一組類,對外提供一致的服務(wù)接口,這一組類可以是相關(guān)的,也可以是不相關(guān)的,而抽象類則是主為一組相關(guān)的類提供一致的服務(wù)接口。所以說接口往往比抽象類具有更大的靈活性,它允許創(chuàng)建者規(guī)定一個類的基本形式、方法名、自變量列表以及返回類型,但不規(guī)定方法主體。接口也包含了基本數(shù)據(jù)類型的數(shù)據(jù)成員,但它們都默認為static和final。接口只提供一種形式,并不提供實施的細節(jié),這也為其本身及子類提供了較廣泛的空間。

如例三中把Animal定義為一個接口:

 

  1. interface Animal1 {   
  2.   // Compile-time constant:   
  3.   int i = 5// static & final   
  4.   // Cannot have method definitions:   
  5.   void Breath(); // Automatically public   
  6.   String what();   
  7.   void adjust();   
  8.   }   

 

其中的三個方法函數(shù)均沒定義方法體;換言之,接口可以看成只定義了API的協(xié)議規(guī)范,相當(dāng)于C++中的只含有純虛抽象類。其子類Human、Dog、Bird繼承時,必須使用關(guān)鍵字implements或extends從接口實現(xiàn)或繼承。由于接口中只有方法原形,實現(xiàn)接口時無成員變量名字沖突問題,也沒有對父類方法的重定義問題,也不存在重復(fù)繼承問題,比一般類的多態(tài)度繼承簡單。接口繼承形成的層次獨立于類層次,因此允許不同層次中的類實現(xiàn)同一接口,這些實現(xiàn)接口的類支持公共的行為,但實現(xiàn)這些行為的方法可以不同,無須共享任何實現(xiàn)方式,呈現(xiàn)多樣化。同時,這樣的多態(tài)行為使Java的接口的功能的重大意義顯得很明顯。通過接口,每個類都可以自由決定其實現(xiàn)的細節(jié);利用繼承技術(shù),可方便地為一個接口添加新的方法聲明,也可以將幾個接口合并成一個新接口。這樣,實現(xiàn)某一接口的多個類或接口可以以不同的方式實現(xiàn)相同的接口,而每個類或接口仍支持同一組方法,當(dāng)實例化這些類或?qū)崿F(xiàn)接口后,就彌補了Java中“一個子類,只能有一個父類”的不足,實現(xiàn)了多態(tài)性的“一個接口,多種方法”。

4 結(jié)束語

“多態(tài)性”意味著“不同的形式”,是建立對象模型的有力工具。為充分使用多態(tài)性乃至面向?qū)ο蟮募夹g(shù),我們必須將自己的編程視野擴展到不僅包括單獨一個類的成員和消息,也要包括類與類之間的一致性以及它們的關(guān)系。因為只有這樣才可真正有效地加快自己的編程速度、更好地組織代碼、更容易做出包容面廣的程序以及更易對自己的代碼進行維護與擴展。本文對Java中的多態(tài)性及其實現(xiàn)原理進行了深入地解析,目的在于希望學(xué)習(xí)和使用Java語言的程序設(shè)計人員,能更好地掌握開發(fā)Java程序。

【編輯推薦】

  1. 深入Java核心 Java內(nèi)存分配原理精講
  2. 初學(xué)Java語言之多態(tài)初體驗
  3. Java中用接口實現(xiàn)多繼承和多態(tài)的方法
  4. 淺談.NET中不一樣的多態(tài)
責(zé)任編輯:金賀 來源: JavaEye博客
相關(guān)推薦

2009-06-19 14:10:42

Java多態(tài)性

2023-10-20 09:51:00

編程開發(fā)

2009-09-01 15:08:18

C#多態(tài)性

2011-07-11 16:35:28

Java

2011-07-11 16:45:25

JAVA多態(tài)性

2009-08-28 16:48:50

C#多態(tài)性

2009-09-01 14:51:19

C#多態(tài)性

2013-05-30 09:58:31

100G100G技術(shù)100G應(yīng)用

2009-09-24 17:19:06

運行時多態(tài)性

2016-12-12 13:56:39

2010-02-01 14:07:12

C++多態(tài)性

2010-01-28 16:16:32

C++多態(tài)性

2009-11-23 19:33:12

PHP5多態(tài)性

2009-06-16 14:21:49

Eclipse平臺架構(gòu)Eclipse RCP

2023-05-26 00:51:52

2009-01-19 13:54:58

ERP數(shù)據(jù)倉庫應(yīng)用研究

2014-08-21 13:43:26

移動互聯(lián)網(wǎng)租車應(yīng)用研究報告

2009-02-11 10:02:00

2012-11-12 17:27:37

2021-04-07 10:12:36

區(qū)塊鏈技術(shù)商標(biāo)
點贊
收藏

51CTO技術(shù)棧公眾號