Java基礎(chǔ)教程之類型轉(zhuǎn)換與多態(tài)
我們之前使用類創(chuàng)造新的類型(type),并使用繼承來(lái)便利我們創(chuàng)建類的過(guò)程。我將在這一講中深入類型,并介紹多態(tài)(polymorphism)的概念。
類型檢查
Java的任意變量和引用經(jīng)過(guò)類型聲明(type declaration),才能使用。我們之前見(jiàn)過(guò)對(duì)象數(shù)據(jù)、類數(shù)據(jù)、方法參數(shù)、方法返回值以及方法內(nèi)部的自動(dòng)變量,它們都需要聲明其類型。Java是一種強(qiáng)類型(strongly typing)語(yǔ)言,它會(huì)對(duì)類型進(jìn)行檢查。如果我們錯(cuò)誤的使用類型,將造成錯(cuò)誤。
類型不符,賣萌無(wú)效
比如在下面的Test類中,我們將一個(gè)Cup類對(duì)象賦予給aPerson類引用:
public class Test { public static void main(String[] args) { Human aPerson; aPerson = new Cup(); } } class Human { /** * constructor */ public Human(int h) { this.height = h; } /** * accessor */ public int getHeight() { return this.height; } /** * mutator */ public void growHeight(int h) { this.height = this.height + h; } private int height; } class Cup { public void addWater(int w) { this.water = this.water + w; } public void drinkWater(int w) { this.water = this.water - w; } private int water = 0; }
javac將返回:
found : Cup required: Human aPerson = new Cup(); ^ 1 error
基本類型轉(zhuǎn)換
Java可以對(duì)基本類型的變量進(jìn)行類型轉(zhuǎn)換。不同的基本類型有不同的長(zhǎng)度和存儲(chǔ)范圍。如果我們從一個(gè)高精度類型轉(zhuǎn)換到低精度類型,比如從float轉(zhuǎn)換到int,那么我們有可能會(huì)損失信息。這樣的轉(zhuǎn)換叫做收縮變換(narrowing conversion)。這種情況下,我們需要顯示的聲明類型轉(zhuǎn)換,比如:
public class Test { public static void main(String[] args) { int a; a = (int) 1.23; // narrowing conversion System.out.println(a); } }
如果我們從低精度類型轉(zhuǎn)換成高精度類型,則不存在信息損失的顧慮。這樣的變換叫做寬松變換(widening conversion)。我們不需要顯示的要求類型轉(zhuǎn)換,Java可以自動(dòng)進(jìn)行:
public class Test { public static void main(String[] args) { int a = 3; double b; b = a; // widening conversion System.out.println(a); } }
基本類型轉(zhuǎn)換
upcast與多態(tài)
在Java中,引用也可以進(jìn)行類型轉(zhuǎn)換,但是有限制。
我們可以將一個(gè)衍生類引用轉(zhuǎn)換為其基類引用,這叫做向上轉(zhuǎn)換(upcast)或者寬松轉(zhuǎn)換。下面的BrokenCup類繼承自Cup類,并覆蓋了Cup類中原有的addWater()和drinkWater()方法:
public class Test { public static void main(String[] args) { Cup aCup; BrokenCup aBrokenCup = new BrokenCup(); aCup = aBrokenCup; // upcast aCup.addWater(10); // method binding } } class Cup { public void addWater(int w) { this.water = this.water + w; } public void drinkWater(int w) { this.water = this.water - w; } private int water = 0; } class BrokenCup extends Cup { public void addWater(int w) { System.out.println("shit, broken cup"); } public void drinkWater(int w) { System.out.println("om...num..., no water inside"); } }
程序運(yùn)行結(jié)果:
shit, broken cup
在上面可以看到,不需要任何顯示說(shuō)明,我們將衍生類引用aBrokenCup賦予給它的基類引用aCup。類型轉(zhuǎn)換將由Java自動(dòng)進(jìn)行。
我們隨后調(diào)用了aCup(我們聲明它為Cup類型)的addWater()方法。盡管aCup是Cup類型的引用,它實(shí)際上調(diào)用的是BrokenCup的addWater()方法!也就是說(shuō),即使我們經(jīng)過(guò)upcast,將引用的類型寬松為其基類,Java依然能正確的識(shí)別對(duì)象本身的類型,并調(diào)用正確的方法。Java可以根據(jù)當(dāng)前狀況,識(shí)別對(duì)象的真實(shí)類型,這叫做多態(tài)(polymorphism)。多態(tài)是面向?qū)ο蟮囊粋€(gè)重要方面。
多態(tài)是Java的支持的一種機(jī)制,同時(shí)也是面向?qū)ο蟮囊粋€(gè)重要概念。這提出了一個(gè)分類學(xué)的問(wèn)題,既子類對(duì)象實(shí)際上“是”父類對(duì)象。比如一只鳥,也是一個(gè)動(dòng)物;一輛汽車,也必然是一個(gè)交通工具。Java告訴我們,一個(gè)衍生類對(duì)象可以當(dāng)做一個(gè)基類對(duì)象使用,而Java會(huì)正確的處理這種情況。
比如下面的繼承關(guān)系:
我們可以說(shuō)用杯子(Cup)喝水(drinkWater)。實(shí)際上,喝水這個(gè)動(dòng)作具體含義會(huì)在衍生類中發(fā)生很大變換。比如用吸管喝水,和從一個(gè)破杯子喝水,這兩個(gè)動(dòng)作差別會(huì)很大,雖然我們抽象中都講“喝水”。我們當(dāng)然可以針對(duì)每個(gè)衍生類分別編程,調(diào)用不同的drinkWater方法。然而,作為程序員,我們可以對(duì)杯子編程,調(diào)用Cup的drinkWater()方法,而無(wú)論這個(gè)杯子是什么樣的衍生類杯子。Java會(huì)調(diào)用相應(yīng)的正確方法,正如我們?cè)谏厦娉绦蛑锌吹降摹?/p>
看一個(gè)更加有意義的例子,我們給Human類增加一個(gè)drink()方法,這個(gè)方法接收一個(gè)杯子對(duì)象和一個(gè)整數(shù)作為參數(shù)。整數(shù)表示喝水的水量:
public class Test { public static void main(String[] args) { Human guest = new Human(); BrokenCup hisCup = new BrokenCup(); guest.drink(hisCup, 10); } } class Human { void drink(Cup aCup, int w) { aCup.drinkWater(w); } }
程序運(yùn)行結(jié)果:
shit, no water inside
我們?cè)贖uman類的drink()的定義中,要求第一個(gè)參量為Cup類型的引用。但在實(shí)際運(yùn)用時(shí)(Test類),將Cup的BrokenCup衍生類對(duì)象。這實(shí)際上是將hisCup向上轉(zhuǎn)型稱為Cup類,傳遞給drink()方法。在方法中,我們調(diào)用了drinkWater()方法。Java發(fā)現(xiàn)這個(gè)對(duì)象實(shí)際上是BrokenCup對(duì)象,所以實(shí)際調(diào)用了BrokenCup的相應(yīng)方法。
downcast
我們可以將一個(gè)基類引用向下轉(zhuǎn)型(downcast)成為衍生類的引用,但要求該基類引用所指向的對(duì)象,已經(jīng)是所要downcast的衍生類對(duì)象。比如可以將上面的hisCup向上轉(zhuǎn)型為Cup類引用后,再向下轉(zhuǎn)型成為BrokenCup類引用。
Object類型
Java中,所有的類實(shí)際上都有一個(gè)共同的繼承祖先,即Object類。Object類提供了一些方法,比如toString()。我們可以在自己的類定義中覆蓋這些方法。
Object: 祖先
我們可以編寫一個(gè)操作Object對(duì)象的程序,就可以通過(guò)upcast,將任意對(duì)象傳遞給該程序。
我將在以后深入Object類。
(多態(tài)的實(shí)現(xiàn)是依靠RTTI的支持。我將在以后深入。)
總結(jié)
基本類型轉(zhuǎn)換
polymorphism
downcast
Object
- java對(duì)象類型轉(zhuǎn)換和多態(tài)性(實(shí)例講解)
- 詳解Java多態(tài)對(duì)象的類型轉(zhuǎn)換與動(dòng)態(tài)綁定
- java數(shù)據(jù)類型轉(zhuǎn)換陷阱包括列表陷阱
- Java 數(shù)據(jù)類型及類型轉(zhuǎn)換的互相轉(zhuǎn)換實(shí)例代碼
- Java基本數(shù)據(jù)類型與類型轉(zhuǎn)換實(shí)例分析
- 詳解解密Java中的類型轉(zhuǎn)換問(wèn)題
- Java多態(tài)性抽象類與接口細(xì)致詳解
- Java多態(tài)到底都有啥好處
- java中的多態(tài)和繼承示例分析
- Java 之類型轉(zhuǎn)換與多態(tài)詳情
相關(guān)文章
java調(diào)用ffmpeg實(shí)現(xiàn)轉(zhuǎn)換視頻
這篇文章主要為大家詳細(xì)介紹了java調(diào)用ffmpeg實(shí)現(xiàn)轉(zhuǎn)換視頻功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12簡(jiǎn)單了解Spring Cloud Alibaba相關(guān)知識(shí)
這篇文章主要介紹了簡(jiǎn)單了解Spring Cloud Alibaba相關(guān)知識(shí),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10SpringBoot集成ElasticSearch(ES)實(shí)現(xiàn)全文搜索功能
Elasticsearch是一個(gè)開(kāi)源的分布式搜索和分析引擎,它被設(shè)計(jì)用于處理大規(guī)模數(shù)據(jù)集,它提供了一個(gè)分布式多用戶能力的全文搜索引擎,本文將給大家介紹SpringBoot集成ElasticSearch(ES)實(shí)現(xiàn)全文搜索功能,需要的朋友可以參考下2024-02-02MybatisPlus實(shí)現(xiàn)分頁(yè)效果并解決錯(cuò)誤問(wèn)題:cant?found?IPage?for?args
這篇文章主要介紹了MybatisPlus實(shí)現(xiàn)分頁(yè)效果并解決錯(cuò)誤:cant?found?IPage?for?args,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02Java初學(xué)者之五子棋游戲?qū)崿F(xiàn)教程
這篇文章主要為大家詳細(xì)介紹了Java初學(xué)者之五子棋游戲?qū)崿F(xiàn)教程,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-10-10SpringMVC執(zhí)行過(guò)程詳細(xì)講解
MVC是一種軟件設(shè)計(jì)典范,用一種業(yè)務(wù)邏輯、數(shù)據(jù)、界面顯示分離的方法組織代碼,將業(yè)務(wù)邏輯聚集到一個(gè)組件里面,在改進(jìn)和個(gè)性化定制界面及用戶交互的同時(shí),不需要重新編寫業(yè)務(wù)邏輯,MVC分層有助于管理和架構(gòu)復(fù)雜的應(yīng)用程序2022-08-08