關于Java三大特性之多態(tài)的總結
面向對象的三大特性:封裝、繼承、多態(tài)。從一定角度來看,封裝和繼承幾乎都是為多態(tài)而準備的。這是我們最后一個概念,也是最重要的知識點。
1.定義:
多態(tài):指允許不同類的對象對同一消息做出響應。即同一消息可以根據(jù)發(fā)送對象的不同而采用多種不同的行為方式。(發(fā)送消息就是函數(shù)調用)
2.實現(xiàn)多態(tài)的技術稱為:動態(tài)綁定(dynamicbinding),是指在執(zhí)行期間判斷所引用對象的實際類型,根據(jù)其實際的類型調用其相應的方法。
3.作用:消除類型之間的耦合關系。
4.現(xiàn)實中,關于多態(tài)的例子不勝枚舉。比方說按下F1鍵這個動作,如果當前在Flash界面下彈出的就是AS3的幫助文檔;如果當前在Word下彈出的就是Word幫助;在Windows下彈出的就是Windows幫助和支持。同一個事件發(fā)生在不同的對象上會產(chǎn)生不同的結果。
5.下面是多態(tài)存在的三個必要條件,要求大家做夢時都能背出來!
多態(tài)存在的三個必要條件
一、要有繼承;
二、要有重寫;
三、父類引用指向子類對象。
6.多態(tài)的好處:
1)可替換性(substitutability):多態(tài)對已存在代碼具有可替換性。例如,多態(tài)對圓Circle類工作,對其他任何圓形幾何體,如圓環(huán),也同樣工作。
2)可擴充性(extensibility):多態(tài)對代碼具有可擴充性。增加新的子類不影響已存在類的多態(tài)性、繼承性,以及其他特性的運行和操作。實際上新加子類更容易獲得多態(tài)功能。例如,在實現(xiàn)了圓錐、半圓錐以及半球體的多態(tài)基礎上,很容易增添球體類的多態(tài)性。
3)接口性(interface-ability):多態(tài)是超類通過方法簽名,向子類提供了一個共同接口,由子類來完善或者覆蓋它而實現(xiàn)的。如圖8.3所示。圖中超類Shape規(guī)定了兩個實現(xiàn)多態(tài)的接口方法,computeArea()以及computeVolume()。子類,如Circle和Sphere為了實現(xiàn)多態(tài),完善或者覆蓋這兩個接口方法。
4)靈活性(flexibility):它在應用中體現(xiàn)了靈活多樣的操作,提高了使用效率。
5)簡化性(simplicity):多態(tài)簡化對應用軟件的代碼編寫和修改過程,尤其在處理大量對象的運算和操作時,這個特點尤為突出和重要。
貓狗案例代碼
class Animal { public void eat(){ System.out.println("eat"); } public void sleep(){ System.out.println("sleep"); } } class Dog extends Animal { public void eat(){ System.out.println("狗吃肉"); } public void sleep(){ System.out.println("狗站著睡覺"); } } class Cat extends Animal { public void eat() { System.out.println("貓吃魚"); } public void sleep() { System.out.println("貓趴著睡覺"); } } class Pig extends Animal { public void eat() { System.out.println("豬吃白菜"); } public void sleep() { System.out.println("豬側著睡"); } } //針對動物操作的工具類 class AnimalTool { private AnimalTool(){ } /* //調用貓的功能 public static void useCat(Cat c) { c.eat(); c.sleep(); } //調用狗的功能 public static void useDog(Dog d) { d.eat(); d.sleep(); } //調用豬的功能 public static void usePig(Pig p) { p.eat(); p.sleep(); } */ public static void useAnimal(Animal a) { a.eat(); a.sleep(); } //把所有的可能都歸為動物類 } class DuoTaiDemo2 { public static void main(String[] args) { //我喜歡貓,就養(yǎng)了一只 Cat c = new Cat(); c.eat(); c.sleep(); //我很喜歡貓,所以,又養(yǎng)了一只 Cat c2 = new Cat(); c2.eat(); c2.sleep(); //我特別喜歡貓,又養(yǎng)了一只 Cat c3 = new Cat(); c3.eat(); c3.sleep(); //... System.out.println("--------------"); //問題來了,我養(yǎng)了很多只貓,每次創(chuàng)建對象是可以接受的 //但是呢?調用方法,你不覺得很相似嗎?僅僅是對象名不一樣。 //我們準備用方法改進 //調用方式改進版本 //useCat(c); //useCat(c2); //useCat(c3); //AnimalTool.useCat(c); //AnimalTool.useCat(c2); //AnimalTool.useCat(c3); AnimalTool.useAnimal(c); AnimalTool.useAnimal(c2); AnimalTool.useAnimal(c3); System.out.println("--------------"); //我喜歡狗 Dog d = new Dog(); Dog d2 = new Dog(); Dog d3 = new Dog(); //AnimalTool.useDog(d); //AnimalTool.useDog(d2); //AnimalTool.useDog(d3); AnimalTool.useAnimal(d); AnimalTool.useAnimal(d2); AnimalTool.useAnimal(d3); System.out.println("--------------"); //我喜歡寵物豬 //定義一個豬類,它要繼承自動物,提供兩個方法,并且還得在工具類中添加該類方法調用 Pig p = new Pig(); Pig p2 = new Pig(); Pig p3 = new Pig(); //AnimalTool.usePig(p); //AnimalTool.usePig(p2); //AnimalTool.usePig(p3); AnimalTool.useAnimal(p); AnimalTool.useAnimal(p2); AnimalTool.useAnimal(p3); System.out.println("--------------"); //我喜歡寵物狼,老虎,豹子... //定義對應的類,繼承自動物,提供對應的方法重寫,并在工具類添加方法調用 //前面幾個必須寫,我是沒有意見的 //但是,工具類每次都改,麻煩不 //我就想,你能不能不改了 //太簡單:把所有的動物都寫上。問題是名字是什么呢?到底哪些需要被加入呢? //改用另一種解決方案。 } /* //調用貓的功能 public static void useCat(Cat c) { c.eat(); c.sleep(); } //調用狗的功能 public static void useDog(Dog d) { d.eat(); d.sleep(); } */ }
7.Java中多態(tài)的實現(xiàn)方式:接口實現(xiàn),繼承父類進行方法重寫,同一個類中進行方法重載。
8.Java中多態(tài)的分類:
在java中,多態(tài)大致可以分為以下幾種情況:
1)person為父類,student為子類。那么:personp=newstudent();
2)fliable為接口,bird為實現(xiàn)接口的類,那么:fliablef=newbird();
3)fliable為抽象類,bird為繼承fliable的類,那么:fliablef=newbird();
多態(tài)時需要說明p聲明為父類的引用,但他實際為子類引用。但是他只能調用父類中的方法。如果子類中的方法覆蓋了父類方法,那么將調用父類方法(虛方法調用)。接口多態(tài)也是同樣的,也許你會問,如果f要調用自己的方法,那豈不是出錯了?其實這里也是方法的覆蓋,因為實現(xiàn)接口的子類肯定會實現(xiàn)接口中的方法,所以此種情況下調用的是bird中的方法。但是如果bird有一個方法在接口中沒有定義,那么f不能調用。
9.instanceof運算符:
java語言的多態(tài)機制導致了引用變量的聲明類型和其實際引用對象的類型可能不一致,再結合虛方法調用規(guī)則可以得出結論:聲明為同種類型的兩個引用變量調用同一個方法時也可能會有不同的行為。這里就引入了instanceof運算符。
那么如果我聲明了personp=newstudent();我想將p轉為student的可不可以?當然可以,但是就得強制轉換了(兒子想成為父親直接來,父親想成為兒子你就強來)。
通常在強制轉換時加上instanceof來判斷。
if(pinstanceofstudent){students=(student)p;}
多態(tài)貫穿于java整個學習,比如在異常處理時寫catch語句,我們規(guī)定必須子類異常寫在前,父類異常寫在后。為什么呢?原因就是多態(tài)了。我們的catch語句格式:catch(Exceptione)。java程序在產(chǎn)生異常時會自動生成一個異常對象,如果先產(chǎn)生一個子類異常,并且父類異常寫在前,那么根據(jù)多態(tài)肯定會執(zhí)行此catch語句,執(zhí)行完一條catch語句后將會跳出。
10.實例:
關于JAVA的多態(tài)性雖然自己也不是很懂,但是下面的這個例子讓我理解了一些:
class A { public String show(D obj)...{ return ("A and D"); } public String show(A obj)...{ return ("A and A"); } } class B extends A { public String show(B obj)...{ return ("B and B"); } public String show(A obj)...{ return ("B and A"); } } class C extends B{ } class D extends B{ } class E { public static void main(String [] args) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println(a1.show(b)); //① System.out.println(a1.show(c)); //② System.out.println(a1.show(d)); //③ System.out.println(a2.show(b)); //④ System.out.println(a2.show(c)); //⑤ System.out.println(a2.show(d)); // ⑥ System.out.println(b.show(b)); //⑦ System.out.println(b.show(c)); //⑧ System.out.println(b.show(d)); //⑨ } }
(三)答案
① A and A ② A and A ③ A and D ④ B and A ⑤ B and A ⑥ A and D ⑦ B and B ⑧ B and B ⑨ A and D
****有個好心人的解答****
該問題的關鍵有兩點:
一是子類與父類的關系,二是重載方法的調用問題。
子類對象可以直接當成父類對象使用,但反過來就不可以。舉例來說,人是父類,學生是人的子類,所以學生對象一定具備人對象的屬性,但是人對象就未必具有學生對象的特性。所以學生對象可以當做人對象來使用,但是人對象就不能當做學生對象使用。注意當把子類對象當成父類對象使用時,子類對象將失去所有的子類特性,只保留與父類同名的屬性和方法(同名方法不僅是函數(shù)名相同,而且參數(shù)類型也要一樣,否則不予保留)。
一個類中如果定義了重載的方法,則系統(tǒng)在調用方法時,會根據(jù)參數(shù)的類型自動選擇調用合適的方法。
1)a1.shows(b),在A中沒有含有B類參數(shù)的方法,但是含有A類參數(shù)的方法,根據(jù)子類對象父類可用的原則,所以調用方法
publicStringshow(Aobj)...{return("AandA");}
2)a1.show(c),C類是B類的子類,而B類又是A類的子類,所以C類對象可以當制作A類對象使用。結果同上。
3)a1.show(d),根據(jù)參數(shù)類型直接調用A中的方法
publicStringshow(Dobj)...{
return("AandD");}
4)a2.show(b),a2本來是一個B對象,但是將其賦給了A類變量,所以a2只保留了與父類A同名的屬性和方法。a2.show(b)調用B類中的保留的與父類同名同參方法
public String show(A obj)...{
return ("B and A");
}
5) a2.show(c),B類的保留方法中沒有C類參數(shù)方法,但是有含有C的父類B的參數(shù)方法,所以調用的方法
public String show(A obj)...{
return ("B and A");
}
我覺得這樣解釋更合理:a2本來是類B的一個對象,但是又將值賦給了類A,C是B的子類,B是A的子類,因此a2保留了類B中與A同名的屬性和方法。
6) a2.show(d),調用的是A類中的
public String show(D obj)...{
return ("A and D");
}
7) b.show(b),調用B類中的
public String show(B obj)...{
return ("B and B");
}
8) b.show(c),B類中沒有C類參數(shù)的方法,但是有B類參數(shù)的方法,所以調用方法
public String show(B obj)...{
return ("B and B");
}
9) b.show(d),解釋同8
總結
以上就是本文關于Java多態(tài)性的總結的全部內容,希望對大家有所幫助。有什么問題可以隨時留言,期待您的寶貴意見!
相關文章
關于eclipse中運行tomcat提示端口被占用的4種解決
這篇文章主要介紹了關于eclipse中運行tomcat提示端口被占用的4種解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01java sql ResultSet 之getRow()用法說明
這篇文章主要介紹了java sql ResultSet 之getRow()用法說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08Spring\SpringBoot配置連接數(shù)據(jù)庫的方法
最近在學習SpringBoot,第一步就是要配置數(shù)據(jù)庫,本文詳細的介紹了Spring\SpringBoot配置連接數(shù)據(jù)庫的方法,有需要的朋友們下面隨著小編來一起學習學習吧2021-06-06SpringBoot+websocket實現(xiàn)消息對話功能
WebSocket是一種在Web應用程序中實現(xiàn)實時雙向通信的技術,它可以用于在線游戲、在線聊天、推送通知、實時監(jiān)控等,并且比傳統(tǒng)的輪詢技術更加高效和可靠,本文就給大家介紹基于SpringBoot+websocket實現(xiàn)消息對話功能,感興趣的小伙伴可以自己動手試一試2023-09-09