成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

深入解析Java的多態性及應用研究

開發 后端
多態性是面向對象的重要特性之一。利用多形性的概念,可改善程序代碼的組織以及可讀性,還能創建“易于擴展”的程序。通過深入研究Java多態性的實現原理,解析具體實例,演示了多態性在程序設計中的應用。

摘要:多態性是面向對象的重要特性之一。利用多形性的概念,可改善程序代碼的組織以及可讀性,還能創建“易于擴展”的程序。通過深入研究Java多態性的實現原理,解析具體實例,演示了多態性在程序設計中的應用。

關鍵詞:多態;繼承;方法;抽象類;接口

中圖分類號:TP391文獻標識碼: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(多態)”一詞來自希臘語,意為“多種形式”。多態在面向對象語言中是個很普遍的概念,同時也是對象開發軟件的一個特殊特性,指的是一個程序中同名的不同方法共存的情況。Java語言支持兩種類型的多態性:運行時的多態性和編譯時的多態性。運行時的特性(動態多態性)是指Java中的動態多態性實現手段---覆蓋(替換)基類中的同名成員函數(函數原型一致),其調用規則是依據對象在實例化時而非定義時的類型相應地調用對應類中的同名成員函數。編譯時的特性(靜態多態性)是指Java中的靜態多態性實現手段-----重載函數,其調用規則是依據對象在定義時的類型相應地調用對應類中的重載函數。Java多態性的主要表現形式有:繼承多態、抽象多態和接口多態。

1 繼承實現的多態

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

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

1.1方法的覆蓋

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

代碼示例一:

 

  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.   }}   

 

程序運行結果為:

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

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

1.2函數的重載

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

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

構造函數的多態性就是典型函數重載情況。

代碼示例二:

 

  1.  import java.io.*;   
  2.   class Gz   
  3.   {//第一種構造函數   
  4.   publicGz(){System.out.println("這個構造函數的參數是:空");   
  5.     }   
  6.   publicGz(int s)   
  7.   {//第二種構造函數   
  8.   System.out.println("這個構造函數的參數是:整數");   
  9.   }   
  10.   publicGz(char m)   
  11.   {//第三種構造函數   
  12.   System.out.println("這個構造函數的參數是:字符型");   
  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.   }}   

 

運行結果:

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

同樣地,子類也可以根據實際情況對其父類的構造函數進行覆蓋,有異曲同工的效果。但應注意:子類如果有多個構造函數的時候,父類要么沒有構造成函數,讓編譯器自動產生,那么在執行子類構造函數之前先執行編譯器自動產生的父類缺省的構造函數;要么至少要有一個顯式的缺省構造函數可以讓子類的構造函數調用。

2 抽象類實現的多態

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

代碼示例三:

 

  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); }}   

 

運行結果:

其邏輯結構如下圖:

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

3 接口實現的多態

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

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

如例三中把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.   }   

 

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

4 結束語

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

【編輯推薦】

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

2009-06-19 14:10:42

Java多態性

2023-10-20 09:51:00

編程開發

2009-09-01 15:08:18

C#多態性

2011-07-11 16:35:28

Java

2009-08-28 16:48:50

C#多態性

2011-07-11 16:45:25

JAVA多態性

2009-09-01 14:51:19

C#多態性

2013-05-30 09:58:31

100G100G技術100G應用

2016-12-12 13:56:39

2009-09-24 17:19:06

運行時多態性

2010-02-01 14:07:12

C++多態性

2009-06-16 14:21:49

Eclipse平臺架構Eclipse RCP

2010-01-28 16:16:32

C++多態性

2009-01-19 13:54:58

ERP數據倉庫應用研究

2023-05-26 00:51:52

2009-11-23 19:33:12

PHP5多態性

2009-02-11 10:02:00

2014-08-21 13:43:26

移動互聯網租車應用研究報告

2012-11-12 17:27:37

2021-04-07 10:12:36

區塊鏈技術商標
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美综合色 | 欧美色专区 | 一区二区伦理电影 | 免费在线观看一区二区 | 美女黄色在线观看 | 国产精品不卡视频 | 国产精品国产a级 | 黄色在线免费看 | 亚洲成人二区 | 国产欧美一区二区三区在线看 | 二区中文字幕 | 欧美日韩黄| 色噜噜狠狠色综合中国 | 国产精品日本一区二区在线播放 | 在线成人免费视频 | 99精品电影| 人人干人人艹 | 97超碰人人草 | 欧美日韩亚洲三区 | 日本三级全黄三级三级三级口周 | 91精品国产综合久久久久久首页 | 久久激情av | 日韩a | 久久三区 | 成人在线免费视频观看 | 少妇久久久| 夜夜夜夜夜夜曰天天天 | 亚洲在线看 | 日日碰狠狠躁久久躁96avv | 欧美一级免费片 | 国产成人精品免费视频 | 欧美精品免费观看二区 | 国产精品久久视频 | 亚洲精品美女在线观看 | 波多野结衣先锋影音 | 亚洲免费观看视频网站 | 美国一级毛片a | 二区高清| av免费入口 | 国产午夜精品一区二区三区嫩草 | 国产在线播 |