【JavaSE系列】 第九话 —— 多态那些事儿
?導航小助手?
? 🍚前言
? 🍞思維導圖
? 🧇一、多態的概念
? 🧀二、向上轉型和向下轉型
? ? ? ? ? ? ? 🥡🥡2.1 向上轉型
? ? ? ? ? ? ? 🥨🥨2.2?什么是向上轉型
? ? ? ? ? ? ? 🥐🥐2.3?三種常見的向上轉型
? ? ? ? ? ? ? ? ? ? ? ? 🍔🍔🍔2.3.1?直接賦值
? ? ? ? ? ? ? ? ? ? ? ? 🍜🍜🍜2.3.2?作為方法的參數
? ? ? ? ? ? ? ? ? ? ? ? 🎂🎂🎂2.3.3?作為方法的返回值
? ? ? ? ? ? ? 🍤🍤2.4?向下轉型(這個了解即可)
? 🍰三、方法重寫
? ? ? ? ? ? ? 🍣🍣3.1 方法重寫的概念
? ? ? ? ? ? ? 🦪🦪3.2 方法重寫的規定
? ? ? ? ? ? ? 🥩🥩3.3 在IDEA中使用重寫的快捷方式???????
? ? ? ? ? ? ? 🍱🍱3.4 方法重寫中所要注意的細節
? 🍛四、多態
? ? ? ? ? ? ? 🍖🍖4.1 什么是多態
? ? ? ? ? ? ? 🥮🥮4.2 多態產生的前提
? 🍝五、理解多態
? 🥣六、多態的優缺點
? ? ? ? ? ? ? 🥗🥗6.1 使用多態的好處???????
? ? ? ? ? ? ? 🍗🍗6.2 多態的缺點
? 🍲七、避免在構造方法中調用重寫的方法
? 🍎寫在最后
前言
? ? ? ?本篇博客 博主來介紹 Java的三大特性的最后一個 特性 —— 多態;
? ? ? ?當然,也包括多態所涉及的多方面內容;
? ? ? ?現在,拉長耳朵,提高警覺,端起你們的小板凳;
? ? ? ?且聽我細細道來......
思維導圖
?
一、多態的概念
? ? ? ?多態,
? ? ? ?從語文的層次上來說:一種事務,多種形態;這句話不算對,但也不算錯;
? ? ? ?但是,我們需要從程序的角度上來介紹:去完成某個行為,當不同的對象去完成時,會產生不同的狀態,這就是多態。
? ? ? ?比如說,如下圖所示:同樣是一個打印機,去打印相同的照片;但是,交給彩色打印機打印出來的就是彩色的照片;交給黑白打印機打印出來的就是黑白照片;它們完成的動作都是“打印”;這就是一種多態;
? ? ? ?再比如說,如下圖所示,去“吃飯”,對于小貓來說,吃的是“貓糧”;但對于小狗來說,吃的確是“狗糧”;他們完成的都是“吃飯”這個行為,但是卻“吃出不同的結果來”; 這也是一種多態;
總的來說,同一件事情,發生在不同的對象上,會產生不同的結果。?
聽到這里,是不是還是對于 多態 有點頭暈;
那么,要想真正了解多態,我們還是需要從三個方面來介紹:
下面,我會一一的介紹......
二、向上轉型和向下轉型
2.1 向上轉型
? ? ? ?當然的是,有了 向上轉型,那么肯定也會有向下轉型,
向下轉型 會在后面講到......
2.2?什么是向上轉型
? ? ? ?首先介紹一段平平常常的繼承代碼:
package Demo1; class Animal {public String name;public int age;public void eat() {System.out.println(this.name+"吃飯!");} }class Cat extends Animal {public String hair;public void mew() {System.out.println(this.name+"正在叫!");} }public class TestDemo1 {public static void main(String[] args) {Cat cat = new Cat();cat.mew();} }? ? ? ?那么,如果現在拋開 繼承 不談,直接用Animal類 new一個animal對象,可以發現,animal對象訪問不了Animal類 里面沒有的成員變量 或成員方法:
? ? ? ?接下來,可以來講一講 向上轉型 的知識了:
? ? ? ?這里的 上 指的是 父類,那么 下 指的就是 子類;
? ? ? ? 那么,把子類給父類是什么意思呢?
//即:定義類一個 cat//可以用animal來接收//也就是說,父類的引用 可以用來引用 子類的對象Cat cat = new Cat();Animal animal = cat;//也就是說,上面的兩行代碼,可以合并成下面一行代碼Animal animal = new Cat();//此時,父類的引用 引用了 子類的對象,我們把這個就叫做 向上轉型? ? ? ?但是,此時又有一個新的問題;
? ? ? ?animal的類型是Animal,那么 此時它只能去訪問 類Animal 的成員變量和方法,去訪問 子類Cat的成員變量或方法的時候會報錯:
?
【總結】
? ? ? ?向上轉型,把原來的 子類的類型 轉換成了 父類的類型,那么,就只能去訪問 父類特有的成員方法或者成員變量。
2.3?三種常見的向上轉型
2.3.1?直接賦值
? ? ? ?所謂直接賦值,就是 上面的直接把 子類對象 給 父類 進行引用:
/*Cat cat = new Cat();Animal animal = cat;*/Animal animal = new Cat();2.3.2?作為方法的參數
2.3.3?作為方法的返回值
2.4?向下轉型(這個了解即可)
前面已經介紹過 向上轉型,那么 現在來介紹一下 向下轉型:
不過,現在來執行一下這樣的操作:
此時,運行結果:
但是,向下轉型不安全(不介意使用向下轉型):
?我們還需要做以下修改 以保證其安全性:
【注意】
三、方法重寫
? ? ? ?由上面可知,父類引用引用了子類的對象;
? ? ? ?但是,在現實生活中,貓是吃貓糧的;
? ? ? ?那么,如果想改的話,肯定不可以在父類上面進行修改的;
? ? ? ?畢竟,可能還有 其他的子類 來繼承父類;
? ? ? ?那么,如果想修改的話,就需要在子類里面重新取實現一遍這個方法的:
? ? ? ?然后,我們來對比一下 實現前后的結果:
沒有在子類里面寫eat方法:
在子類里面寫了eat方法:
?這是怎么回事呢?
——這就是馬上所要介紹的方法重寫。
3.1 方法重寫的概念
? ? ? ?重寫,也稱為覆蓋;
? ? ? ?重寫,是子類對父類 非靜態、非private修飾、非final修飾、非構造方法 等的實現過程進行重新編寫;
? ? ? ?重寫的好處是:子類可以根據需要,定義特定的屬于自己的行為;如 上面的貓可以吃貓糧,狗可以吃狗糧。
3.2 方法重寫的規定
方法重寫滿足以下三個條件:
? ? ? ?當在子類 方法重寫以后,那么就會調用的是 子類重寫的內容。
? ? ? ?我們把這個現象叫做動態綁定(這是多態的基礎)
? ? ? ?傳送門:動態綁定
? ? ? ?在上面所示例中,
? ? ? ?在編譯的時候,調用的還是 父類Animal的eat方法;
? ? ? ?但是,在運行的時候,變成了子類Cat自己的eat方法;
? ? ? ?因此,動態綁定又稱為 運行時綁定,
? ? ? ?即:在程序運行的時候才知道要調用誰。
? ? ? ?當然,有了 動態綁定,那肯定也有 靜態綁定:
? ? ? ?在編譯期間就已經知道了 要調用的是誰,
? ? ? ?比如說 重載。
3.3 在IDEA中使用重寫的快捷方式
? ? ? ?當然,在使用IDEA編譯器的時候 ,
? ? ? ?重寫不僅僅可以直接在子類上手敲出來的(上面的就是),而且還可以使用快捷鍵的方式:
?
【注意】上面的 @Override 就是重寫的意思。
?
3.4 方法重寫中所要注意的細節
?訪問限定符權限大小比較:
private < default < peotected < public??
?
四、多態
4.1 什么是多態
類的實現者所寫的代碼:
class Animal {public String name;public int age;public void eat() {System.out.println(this.name+"吃飯!父類Animal");} }class Cat extends Animal {public String hair;public void eat(){System.out.println(this.name+"吃貓糧!");}public void mew() {System.out.println(this.name+"正在叫!");} } class Dog extends Animal {public void eat(){System.out.println(this.name+"吃狗糧!");} }類的調用者所寫的代碼:
public static void function(Animal animal) {animal.eat();}public static void main(String[] args) {Cat cat = new Cat();Dog dog = new Dog();function(cat);function(dog);}?
所以運行之后得到的結果不一樣:
? ? ? ?從上面可以得到,同一個方法,當引用的對象不一樣的時候,這個方法所表現出來的行為是不一樣的;
? ? ? ?我們把這種思想就叫做 多態。?
4.2 多態產生的前提
思想:通過一個引用調用一個方法,由于引用的對象不同,所執行的行為也是不一樣的;我們把這種思想就叫做多態的思想。
五、理解多態
現在再次回顧一下多態:
場景:現在想畫一個圖形(圖形是未知的):
首先,創建父類:
class Shape {//省略了長、寬、高等之類的屬性public void draw(){System.out.println("畫圖形!!!!!!");}}創建父類Shape只是畫父類,但是并沒有說明畫什么;
現在想畫各種各樣的圖形,那么就可以去重寫 Shape類里面的draw方法來滿足自己的需求:
class Cycle extends Shape {@Overridepublic void draw() {System.out.println("○");} }class Rect extends Shape {@Overridepublic void draw() {System.out.println(" ? ");} }class Triangle extends Shape {@Overridepublic void draw() {System.out.println("△");} }前面兩段代碼都是類的實現者寫的;
當有一天作為用戶、作為類的調用者 想要畫出這些圖形,那么就可以這樣來做:
public static void drawMap(Shape shape) {shape.draw();}public static void main(String[] args) {Cycle cycle = new Cycle();Rect rect = new Rect();Triangle triangle = new Triangle();drawMap(cycle);drawMap(rect);drawMap(triangle);}那么,根據引用的對象不一樣,draw方法所表現的行為就不一樣;
這個就叫做 多態。
代碼示例結果:
由此可見,多態只是一種思想,需要滿足三個條件;
那么,多態到底有什么好處呢?
——其拓展能力非常強:
如果突然說,現在想要畫一朵花:
那么只需要在這樣做即可:
class Flower extends Shape {@Overridepublic void draw() {System.out.println("?");} }測試類添上這個來測試:
drawMap(new Flower());代碼示例結果:
六、多態的優缺點
6.1 使用多態的好處
(1)能夠降低代碼的 "圈復雜度" ,避免使用大量的 if-else語句;
? ? ? ? ? ??傳送門——圈復雜度??????
? ? ? ? ? ?說白了,可以簡單粗暴的計算 一段代碼中條件語句和循環語句 出現的個數,這個個數就稱為 "圈復雜度";
? ? ? ? ? ? 如果一個方法的 圈復雜度 太高,就需要考慮重構。
(2)可擴展能力強;?
? ? ? ? ? ? 就是上面所說的 添加了一朵花的 示例。
6.2 多態的缺點
? ? ? ? ? ? ? ? ? ? ?代碼的運行效率低。
七、避免在構造方法中調用重寫的方法
class B {public B(){func();}public void func() {System.out.println("B.func() ");} }class D extends B {D(){super();}@Overridepublic void func() {System.out.println("D.func() ");} }public class Test {public static void main(String[] args) {D d = new D();} }代碼示例結果:
?【說明】
【注意】最好盡量不要寫類似的代碼——避免在構造方法中調用重寫的方法。
寫在最后
? ? ? ?到現在,Java三大特性的最后一個特性——多態思想 就已經告一段落了;
? ? ? ?由于博主水平有限,可能會出現一些表達不清楚,或者出現一些其他的情況,
? ? ? ?歡迎各位鐵汁們指出來,和博主一起改正,
? ? ? ?一起努力,共同進步;
? ? ? ?好了,如果這篇博客對鐵汁們有幫助的話,可以送一個免費的 贊 嘛;
? ? ? ?當然,順手點個關注是再好不過的了......
?
總結
以上是生活随笔為你收集整理的【JavaSE系列】 第九话 —— 多态那些事儿的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue3运行npm run serve报
- 下一篇: 搭建react + typescript