【Java探索之旅】多態:向上下轉型、多態優缺點、構造函數陷阱

文章目錄

  • 📑前言
  • 一、向上轉型和向下轉型
    • 1.1 向上轉型
    • 1.2 向下轉型
  • 二、多態的優缺點
    • 2.1 多態優點
    • 2.2 多態缺陷
  • 三、避免避免構造方法中調用重寫的方法
  • 四、好的習慣
  • 🌤?全篇總結

📑前言

在面向對象編程中,向上轉型和向下轉型是常用的技術手段,可以實現不同類之間的轉換和靈活應用。同時,多態作為面向對象編程的重要特性,具有諸多優點和缺陷,對代碼的設計和性能都有一定影響。本文將深入探討向上轉型、向下轉型以及多態的優缺點,幫助讀者更好地理解和運用這些概念在Java編程中的實際應用和注意事項。

一、向上轉型和向下轉型

1.1 向上轉型

實際就是創建一個子類對象,將其當成父類對象來使用。

語法格式:父類類型 對象名 = new 子類類型()

Animal animal = new Cat(“小小”,3);

animal是父類類型,但可以引用一個子類對象,因為是從小范圍向大范圍的轉換。

使用場景

  1. 直接賦值
  2. 方法傳參
  3. 方法返回
class TestAnimal {// 2. 方法傳參:形參為父類型引用,可以接收任意子類的對象public static void eatFood(Animal a){a.eat();} // 3. 作返回值:返回任意子類對象public static Animal buyAnimal(String var){if("狗".equals(var) ){return new Dog("狗狗",1);}else if("貓" .equals(var)){return new Cat("貓貓", 1);}else{return null;}}public static void main(String[] args) {// 1. 直接賦值:子類對象賦值給父類對象Animal cat = new Cat("元寶",2); Dog dog = new Dog("小七", 1);eatFood(cat);eatFood(dog);Animal animal = buyAnimal("狗");animal.eat();animal = buyAnimal("貓");animal.eat();}
}

**向上轉型的優點:**讓代碼實現更簡單靈活。

**向上轉型的缺陷:**不能調用到子類特有的方法。

1.2 向下轉型

將一個子類對象經過向上轉型之后當成父類方法使用,再無法調用子類的方法,但有時候可能需要調用子類特有的方法,此時:將父類引用再還原為子類對象即可,即向下轉換。

public static void main(String[] args) {Animal animal1 = new Dog("小七",7);//向上轉型Animal animal2 = new Cat("咪咪",3);//向上轉型animal1 = (Dog)animal1;//向下轉型animal2 = (Cat)animal1;//向下轉型編譯報錯,因為animal1實際上是指向的是Dog,強制轉化為Cat無法還原}

向下轉型用的比較少,而且不安全,萬一轉換失敗,運行時就會拋異常。Java中為了提高向下轉型的安全性,引入了 instanceof ,如果該表達式為true,則可以安全轉換。

二、多態的優缺點

2.1 多態優點

  1. 提高代碼的可擴展性和可維護性:通過多態,可以將具體的實現與抽象的接口分離,使得系統的各個模塊之間的耦合度降低,從而方便對系統進行擴展和維護。
  2. 增強代碼的靈活性:通過多態,可以在運行時動態地決定對象的具體類型,從而實現不同對象的不同行為。這樣可以根據實際需求靈活地進行對象的選擇和使用。
  3. 提高代碼的可讀性和可理解性:通過多態,可以將對象的具體類型隱藏起來,只關注對象的抽象類型和接口,從而使得代碼更加簡潔、清晰,易于理解和閱讀
  4. 能夠降低代碼的 “圈復雜度”, 避免使用大量的 if - else

擴展

  • 圈復雜度是一種描述一段代碼復雜程度的方式. 一段代碼如果平鋪直敘, 那么就比較簡單容易理解. 而如果有很多的條件分支或者循環語句, 就認為理解起來更復雜.
  • 因此我們可以簡單粗暴的計算一段代碼中條件語句和循環語句出現的個數, 這個個數就稱為 “圈復雜度”。如果一個方法的圈復雜度太高, 就需要考慮重構,不同公司對于代碼的圈復雜度的規范不一樣. 一般不會超過 10 。
class Book{public void read(){System.out.println("看書");}
}
class English extends Book{public void read(){System.out.println("看英語書");}
}
class Maths extends Book{public void read(){System.out.println("看數學書");}
}
class Language extends Book{@Overridepublic void read() {System.out.println("看語文書");}
}
public class Exercise3 {public static void readBook(){English english = new English();Maths maths = new Maths();Language language = new Language();Book[] book = {english,language,maths,language,maths,english};for (Book x:book) {x.read();}}public static void main(String[] args) {readBook();}
}

2.2 多態缺陷

性能損失:由于多態需要在運行時進行類型的判斷和方法的動態綁定,所以會帶來一定的性能損失。相比于直接調用具體類型的方法,多態需要進行額外的判斷和查找,從而導致一定的性能下降。

可能引發運行時錯誤:由于多態是在運行時動態決定對象的具體類型,所以如果在使用多態的過程中出現了類型錯誤或者類型轉換錯誤,就會導致運行時錯誤的發生。這就需要在使用多態時進行嚴格的類型檢查和錯誤處理,增加了代碼的復雜性和難度。

可能導致代碼的混亂和難以理解:多態的使用會使得代碼中出現更多的抽象和接口,從而增加了代碼的復雜性和難度。如果使用不當,可能會導致代碼的混亂和難以理解,降低代碼的可讀性和可維護性。因此,在使用多態時需要謹慎設計和使用。

三、避免避免構造方法中調用重寫的方法

class B {public B() {
// do nothingfunc();}public void func() {System.out.println("B.func()");}
}
class D extends B {private int num = 1;@Overridepublic void func() {System.out.println("D.func() " + num);}
}
public class Test {public static void main(String[] args) {D d = new D();}
}
// 執行結果D.func() 0

一段有坑的代碼. 我們創建兩個類, B 是父類, D 是子類. D 中重寫 func 方法. 并且在 B 的構造方法中調用 func。

構造 D 對象的同時, 會調用 B 的構造方法.

B 的構造方法中調用了 func 方法, 此時會觸發動態綁定, 會調用到 D 中的 func

此時 D 對象自身還沒有構造, 此時 num 處在未初始化的狀態, 值為 0. 如果具備多態性,num的值應該是1.

所以在構造函數內,盡量避免使用實例方法,除了final和private方法。

四、好的習慣

“用盡量簡單的方式使對象進入可工作狀態”, 盡量不要在構造器中調用方法(如果這個方法被子類重寫, 就會觸發動態綁定, 但是此時子類對象還沒構造完成), 可能會出現一些隱藏的但是又極難發現的問題。

🌤?全篇總結

向上轉型可以實現子類對象當成父類對象使用,提高代碼的靈活性和復用性;向下轉型則可以讓父類引用還原為子類對象,調用子類特有方法。多態能夠提高代碼的可擴展性和可維護性,但也存在性能損失和潛在的錯誤風險,需要謹慎使用和設計。

避免在構造函數中調用重寫方法,保持構造過程簡潔和清晰,避免潛在的問題。形成良好的編程習慣,能夠提高代碼的質量和可維護性,減少潛在的錯誤和調試成本,是每位Java程序員都應該注意的重要方面。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/42220.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/42220.shtml
英文地址,請注明出處:http://en.pswp.cn/web/42220.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Django 新增數據 create()方法

1,添加模型 Test/app11/models.py from django.db import modelsclass Book(models.Model):title models.CharField(max_length100)author models.CharField(max_length100)publication_date models.DateField()price models.DecimalField(max_digits5, decim…

小米訂單銳減背后的挑戰與應對之道

近期,富士康印度子公司Bharat FIH面臨高管離職、工廠關閉的困境,其背后原因之一是小米訂單的顯著下滑,據報道,這一降幅高達70%。這一現象不僅反映了富士康在印度市場的艱難處境,也揭示了小米在全球智能手機市場面臨的挑…

六、數據可視化—Wordcloud詞云(爬蟲及數據可視化)

六、數據可視化—Wordcloud詞云(爬蟲及數據可視化) 也是一個應用程序 http://amueller.github.io/word_cloud/ Wordcloud詞云,在一些知乎,論壇等有這樣一些東西,要么做封面,要么做講解,進行分析…

C++ | Leetcode C++題解之第223題矩形面積

題目: 題解: class Solution { public:int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2) {int area1 (ax2 - ax1) * (ay2 - ay1), area2 (bx2 - bx1) * (by2 - by1);int overlapWidth min(ax2, bx2) - max…

實戰Qt開發WordBN筆記軟件#01 搭建開發環境:VS2019+Qt6.5+CMake+Git

01 背景 【WordBN字遠筆記】是天恩軟件工作室開發的一款免費筆記軟件;WordBN基于VS2019、Qt6.5開發,使用Qt Quick(QML)開發語言。 本課程將以【WordBN字遠筆記】的界面為實戰基礎,詳細介紹如何基于Qt/QML開發語言&am…

WPF 表格控件斑馬線使用

這里用ListView為案例。 如圖效果: 主要思路: 用AlternationCount屬性來設置需要使用斑馬線的條數,就是說幾行一換色,也可以理解為需要幾種顏色, 然后再樣式模板中,寫觸發器屬性ItemsControl.Alternatio…

python深拷貝和淺拷貝之間的區別是什么?

在Python中,深拷貝和淺拷貝是兩種不同的對象復制機制,它們在復制對象時的行為有顯著差異: 1. 淺拷貝(Shallow Copy): - 淺拷貝創建一個新對象,但它只是復制了原始對象中元素的引用(對于可變…

明明已經安裝了python中的某個庫,但是還是報錯ModuleNotFoundError: No module named ‘sklearn‘

問題: 明明已經安裝了python中的某個庫,但是還是報錯ModuleNotFoundError: No module named sklearn 解決方法: 卸載重新安裝一下即可 pip uninstall scikit-learn pip install scikit-learn 成功解決!!&#xff…

《Windows API每日一練》9.1 資源-圖標

本節講述圖標、鼠標指針位圖、字符串資源表、自定義資源的添加和應用。 本節必須掌握的知識點: 圖標 第56練:ICON圖標資源 鼠標指針位圖 字符串資源表 自定義資源 第57練:字符串資源表和自定義資源 9.1.1 圖標 在 Windows 窗口編程中&…

知識付費系統3.0整站源碼知識付費網課平臺網創資源付費帶自動采集同步插件

程序說明: 1.修復更新到最新版本 2.自動采集插件重寫 3.關閉采集授權域名直接對接 4.更新插件主動請求同步資源 5.帶自動采集插件 原始功能 支持分類替換 將主站同步過來的文章分類進行替換 支持自定義文章作者(選擇多個作者則同步到的文章作者將會隨機分…

java中==和equals()的區別探究

目錄 一、Object對象 二、 三、String類的equals()方法 四、示例 4.1直接定義兩個相同的值比較 4.2直接定義兩個值不同的字符串進行比較 4.3直接定義一個字符串和new一個字符串進行比較(兩者值相同) 4.4直接定義一個字符串和new一個字符串進行…

Halcon Ean13 一維碼讀取

一 EAN碼介紹 1 EAN碼定義: EAN碼是國際物品編碼協會制定的一種商品用條碼,通用于全世界。EAN碼符號有標準版(EAN-13)和縮短版(EAN-8)兩種。標準版表示13位數字,又稱為EAN13碼,縮短版表示8位數…

VScode免密鏈接ubuntu

Ubuntu 下載: sudo apt-get install openssh-serverps -e | grep sshd參考IP : ifconfig VScode配置 重新嘗試連接,輸入的密碼是虛擬機用戶密碼 免密鏈接 Windows生成公鑰 1、打開CMD 2、輸入命令ssh-keygen 3、連續回車確認即可生成 …

正態、威布爾、指數分布、伽馬分布、對數正態分布介紹

目錄 正態、威布爾、指數分布、3.1 概念介紹概率密度函數(PDF)累積分布函數(CDF)性質應用 3.2 參數及繪圖參數概率密度函數(PDF)累積分布函數(CDF)繪圖圖像解讀 3.3 指數分布擬合代碼…

Emacs有什么優點,用Emacs寫程序比IDE更方便嗎?

Emacs 是一款歷史悠久且功能強大的文本編輯器,它以其高度的可定制性和豐富的功能而聞名。在討論 Emacs 的優點以及它是否比 IDE 更方便時,我們需要從多個角度進行深入分析。以下是對 Emacs 優點的詳細闡述,以及它與 IDE 的比較。 Emacs 的優…

第11章 規劃過程組(二)(11.10制訂進度計劃)

第11章 規劃過程組(二)11.10制訂進度計劃,在第三版教材第395~397頁;文字圖片音頻方式 第一個知識點:定義及作用 分析活動順序、持續時間、資源需求和進度制約因素,創建項目進度模型,從而落實項目…

Docker定時清理

一、循環調度執行 1、檢查cron狀態 systemctl status crond 2、創建要執行的shell腳本 vim /home/cleanup_docker.sh #! /bin/bash # 清理臨時文件 echo $(date "%H:%M:%S") "執行docker清理命令..." docker system prune -af-a 清理包括未使用的鏡像 …

Android EditText+ListPopupWindow實現可編輯的下拉列表

Android EditTextListPopupWindow實現可編輯的下拉列表 📖1. 可編輯的下拉列表?步驟一:準備視圖?步驟二:封裝顯示方法?步驟三:獲取視圖并監聽 📖2. 擴展上下箭頭?步驟一:準備上下箭頭icon圖標?步驟二&…

Redisson分布式鎖、可重入鎖

介紹Redisson 什么是 Redisson?來自于官網上的描述內容如下! Redisson 是一個在 Redis 的基礎上實現的 Java 駐內存數據網格客戶端(In-Memory Data Grid)。它不僅提供了一系列的 redis 常用數據結構命令服務,還提供了…

力扣56.合并區間

力扣56.合并區間 按左端點排序 判斷左端點是否小于等于當前右端點**&#xff08;可以合并&#xff09;** class Solution {public:vector<vector<int>> merge(vector<vector<int>>& intervals) {ranges::sort(intervals);vector<vector<i…