首頁 Java java教程 Java中多態性定義與用法分析

Java中多態性定義與用法分析

Sep 28, 2017 am 10:01 AM
java 分析 多態性

這篇文章主要介紹了Java多態性定義與用法,較為詳細的分析了多態的概念、功能以及java定義與實現面向對像多態性的相關操作技巧,需要的朋友可以參考下

本文實例講述了Java多態性定義與用法。分享給大家供大家參考,具體如下:

多態性是透過:

1 介面和實作介面並覆蓋介面中同一方法的幾不同的類體現的

2 父類別和繼承父類別並覆寫父類別中同一方法的幾個不同子類別實現的.

一、基本概念

多態性:傳送訊息給某個對象,讓該對象自行決定回應何種行為。透過將子類別物件引用賦值給超類別物件引用變數來實現動態方法呼叫 。

java 的這種機制遵循一個原則:當超類別物件引用變數引用子類別物件時,被引用物件的類型而不是引用變數的類型決定了呼叫誰的成員方法,但是這個被調用的方法必須是在超類別中定義過的,也就是說被子類別覆蓋的方法。

如果a是類別A的一個引用,那麼,a可以指向類別A的一個實例,或者說指向類別A的一個子類別 。

如果a是介面A的一個引用,那麼,a必須指向實作了介面A的一個類別的實例 。

二、Java多型實作機制

#SUN目前的JVM實作機制,類別實例的參考就是指向一個句柄(handle)的指針,這個句柄是一對指針:

一個指針指向一張表格,實際上這個表格也有兩個指針(一個指針指向一個包含了對象的方法表,另外一個指向類對象,表明該物件所屬的類型);

另一個指標指向一塊從java堆中為分配出來記憶體空間。

三、總結

1、透過子類別物件參考賦值給超類別物件參考變數來實作動態方法呼叫 。


DerivedC c2=new DerivedC();
BaseClass a1= c2; //BaseClass 基类,DerivedC是继承自BaseClass的子类
a1.play(); //play()在BaseClass,DerivedC中均有定义,即子类覆写了该方法
登入後複製

分析:

#1、為什麼子類別的類型的物件實例可以覆寫超類別參考?

自動實現向上轉型 。透過該語句,編譯器會自動將子類別實例向上移動,成為通用型別BaseClass;

2、a.play()將執行子類別還是父類別定義的方法?

子類別的 。在運行時期,將根據a這個物件引用實際的型別來取得對應的方法 。所以才有多態性 。一個基類的物件引用,被賦予不同的子類別物件引用,執行該方法時,將表現出不同的行為 。

在a1=c2的時候,仍然是存在兩個句柄,a1和c2,但是a1和c2擁有同一塊資料記憶體區塊和不同的函數表 。

2、不能把父類別物件引用賦給子類別物件引用變數


BaseClass a2=new BaseClass();
DerivedC c1=a2;//出错
登入後複製

在java裡面,向上轉型是自動進行的,但是向下轉型卻不是,需要我們自己定義強制進行。

c1=(DerivedC)a2; 強制轉換,也就是向下轉型.

3、記住一個很簡單又很複雜的規則,一個型別引用只能引用引用型別本身含有的方法和變數。

你可能說這個規則不對的,因為父類別引用指向子類別物件的時候,最後執行的是子類別的方法的 。

其實這並不矛盾,那是因為採用了後期綁定,動態運行的時候又根據類型去調用了子類別的方法 。而假若子類別的這個方法在父類別中並沒有定義,則會出錯 。

例如,DerivedC類別在繼承BaseClass中定義的函數外,還增加了幾個函數(例如myFun())

分析:

# #當你使用父類別引用指向子類別的時候,其實jvm已經使用了編譯器產生的型別資訊調整轉換了。

這裡你可以這樣理解,相當於把不是父類別中含有的函數從虛擬函數表中設定為不可見的 。注意有可能虛擬函數表中有些函數位址由於在子類別中已經被改寫了,所以物件虛擬函數表中虛擬函數項目位址已經被設定為子類別中完成的方法體的位址了 。

4、Java與C++多態性的比較

jvm關於多態性支援解決方法是和c++中幾乎一樣的,只是c++中編譯器很多是把類型資訊和虛擬函數資訊都放在一個虛擬函數表中,但是利用某種技術來區別。

Java把型別資訊和函數資訊分開 。 Java中繼承以後,子類別會重新設定自己的虛擬函數表,這個虛擬函數表中的專案有由兩個部分組成 。從父類別繼承的虛擬函數和子類別自己的虛擬函數 。

虛擬函數呼叫是經過虛擬函數表間接呼叫的,所以才得以實現多態的 。 Java的所有函數,除了被宣告為final的,都是用後期綁定 。

四. 1个行为,不同的对象,他们具体体现出来的方式不一样,

比如: 方法重载 overloading 以及 方法重写(覆盖)override


class Human{
void run(){输出 人在跑}
}
class Man extends Human{
void run(){输出 男人在跑}
}
登入後複製

这个时候,同是跑,不同的对象,不一样(这个是方法覆盖的例子)


class Test{
void out(String str){输出 str}
void out(int i){输出 i}
}
登入後複製

这个例子是方法重载,方法名相同,参数表不同

ok,明白了这些还不够,还用人在跑举例


Human ahuman=new Man();
登入後複製

这样我等于实例化了一个Man的对象,并声明了一个Human的引用,让它去指向Man这个对象

意思是说,把 Man这个对象当 Human看了.

比如去动物园,你看见了一个动物,不知道它是什么, “这是什么动物? ” “这是大熊猫! “

这2句话,就是最好的证明,因为不知道它是大熊猫,但知道它的父类是动物,所以,这个大熊猫对象,你把它当成其父类 动物看,这样子合情合理.这种方式下要注意 new Man();的确实例化了Man对象,所以ahuman.run()这个方法 输出的 是 “男人在跑 “如果在子类 Man下你 写了一些它独有的方法 比如 eat(),而Human没有这个方法,在调用eat方法时,一定要注意 强制类型转换 ((Man)ahuman).eat(),这样才可以…

对接口来说,情况是类似的…


package domatic;
//定义超类superA
class superA {
int i = 100;
void fun(int j) {
j = i;
System.out.println("This is superA");
}
}
// 定义superA的子类subB
class subB extends superA {
int m = 1;
void fun(int aa) {
System.out.println("This is subB");
}
}
// 定义superA的子类subC
class subC extends superA {
int n = 1;
void fun(int cc) {
System.out.println("This is subC");
}
}
class Test {
public static void main(String[] args) {
superA a = new superA();
subB b = new subB();
subC c = new subC();
a = b;
a.fun(100);
a = c;
a.fun(200);
}
}
登入後複製


/*
* 上述代码中subB和subC是超类superA的子类,我们在类Test中声明了3个引用变量a, b,
* c,通过将子类对象引用赋值给超类对象引用变量来实现动态方法调用 。也许有人会问:
* “为什么(1)和(2)不输出:This is superA” 。
* java的这种机制遵循一个原则:当超类对象引用变量引用子类对象时,
* 被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,
* 但是这个被调用的方法必须是在超类中定义过的,
* 也就是说被子类覆盖的方法 。
* 所以,不要被上例中(1)和(2)所迷惑,虽然写成a.fun(),但是由于(1)中的a被b赋值,
* 指向了子类subB的一个实例,因而(1)所调用的fun()实际上是子类subB的成员方法fun(),
* 它覆盖了超类superA的成员方法fun();同样(2)调用的是子类subC的成员方法fun() 。
* 另外,如果子类继承的超类是一个抽象类,虽然抽象类不能通过new操作符实例化,
* 但是可以创建抽象类的对象引用指向子类对象,以实现运行时多态性 。具体的实现方法同上例 。
* 不过,抽象类的子类必须覆盖实现超类中的所有的抽象方法,
* 否则子类必须被abstract修饰符修饰,当然也就不能被实例化了
*/
登入後複製

以上大多数是以子类覆盖父类的方法实现多态.下面是另一种实现多态的方法———–重写父类方法

1.JAVA里没有多继承,一个类之能有一个父类 。而继承的表现就是多态 。一个父类可以有多个子类,而在子类里可以重写父类的方法(例如方法print()),这样每个子类里重写的代码不一样,自然表现形式就不一样 。这样用父类的变量去引用不同的子类,在调用这个相同的方法print()的时候得到的结果和表现形式就不一样了,这就是多态,相同的消息(也就是调用相同的方法)会有不同的结果 。举例说明:


//父类
public class Father{
//父类有一个打孩子方法
public void hitChild(){
}
}
//子类1
public class Son1 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("为什么打我?我做错什么了!");
}
}
//子类2
public class Son2 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("我知道错了,别打了!");
}
}
//子类3
public class Son3 extends Father{
//重写父类打孩子方法
public void hitChild(){
System.out.println("我跑,你打不着!");
}
}
//测试类
public class Test{
public static void main(String args[]){
Father father;
father = new Son1();
father.hitChild();
father = new Son2();
father.hitChild();
father = new Son3();
father.hitChild();
}
}
登入後複製

都调用了相同的方法,出现了不同的结果!这就是多态的表现!

以上是Java中多態性定義與用法分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

突破或從Java 8流返回? 突破或從Java 8流返回? Feb 07, 2025 pm 12:09 PM

Java 8引入了Stream API,提供了一種強大且表達力豐富的處理數據集合的方式。然而,使用Stream時,一個常見問題是:如何從forEach操作中中斷或返回? 傳統循環允許提前中斷或返回,但Stream的forEach方法並不直接支持這種方式。本文將解釋原因,並探討在Stream處理系統中實現提前終止的替代方法。 延伸閱讀: Java Stream API改進 理解Stream forEach forEach方法是一個終端操作,它對Stream中的每個元素執行一個操作。它的設計意圖是處

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP與Python:了解差異 PHP與Python:了解差異 Apr 11, 2025 am 12:15 AM

PHP和Python各有優勢,選擇應基於項目需求。 1.PHP適合web開發,語法簡單,執行效率高。 2.Python適用於數據科學和機器學習,語法簡潔,庫豐富。

PHP與其他語言:比較 PHP與其他語言:比較 Apr 13, 2025 am 12:19 AM

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP與Python:核心功能 PHP與Python:核心功能 Apr 13, 2025 am 12:16 AM

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

Java程序查找膠囊的體積 Java程序查找膠囊的體積 Feb 07, 2025 am 11:37 AM

膠囊是一種三維幾何圖形,由一個圓柱體和兩端各一個半球體組成。膠囊的體積可以通過將圓柱體的體積和兩端半球體的體積相加來計算。本教程將討論如何使用不同的方法在Java中計算給定膠囊的體積。 膠囊體積公式 膠囊體積的公式如下: 膠囊體積 = 圓柱體體積 兩個半球體體積 其中, r: 半球體的半徑。 h: 圓柱體的高度(不包括半球體)。 例子 1 輸入 半徑 = 5 單位 高度 = 10 單位 輸出 體積 = 1570.8 立方單位 解釋 使用公式計算體積: 體積 = π × r2 × h (4

PHP:許多網站的基礎 PHP:許多網站的基礎 Apr 13, 2025 am 12:07 AM

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

PHP的影響:網絡開發及以後 PHP的影響:網絡開發及以後 Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

See all articles