【Java16】多態

向上類型轉換

對于引用變量,在程序中有兩種形態:一種是編譯時類型,這種引用變量的類型在聲明它的時候就決定了;另一種則是運行時類型,這種變量的類型由實際賦給它的對象決定。

當一個引用變量的編譯時類型和運行時類型不一致時,就出現了多態(Polymorphism)

對面向對象語言來說,所有的對象(Object),或者說類的實例,本質上都是引用變量。因此,多態最主要就是針對對象來說的:聲明時引用變量指向的對象的類型,和運行時引用變量指向的對象的類型不一致。

在這里插入圖片描述

class BaseClass
{public int book = 6;public void base(){System.out.println("父類的普通方法");}public void test(){System.out.println("父類被覆蓋的方法");}
}public class SubClass extends BaseClass
{// 覆蓋public String book = "Java瘋狂講義"; // 同名實例public void test(){System.out.println("子類的覆蓋父類的方法");}public void sub(){System.out.println("子類的普通方法");}public static void main(String[] args){var bc = new BaseClass(); // 聲明一個BaseClass的對象,編譯時和運行時的類型一致,不存在多態System.out.println(bc.book); // 6bc.base(); // 父類的方法bc.test(); // 父類的方法//-------------var sc = new SubClass(); // 聲明一個SubClass的對象,同樣不存在多態System.out.println(sc.book); // 子類實例變量覆蓋了父類的實例變量,輸出"Java瘋狂講義"sc.base(); // 子類方法覆蓋了父類的方法sc.test(); // 子類的普通方法//-------------BaseClass polymophicBC = new SubClass(); // 編譯時類型是BaseClass,運行時類型是SubClass,發生了多態System.out.println(polymophicBC.book); // 輸出6,是父類的實例變量polymophicBC.base(); // 執行父類的base方法polymophicBC.test(); // 執行當前類,也就是運行時類型SubClass的test方法// polymophicBC的編譯時類型是BaseClass,沒有提供sub方法// 因此調用sub方法時會出現編譯錯誤// polymophicBC.sub();}
}
  • 28~31行是標準的對象的聲明與使用;
  • 33~36行是標準的繼承;
  • 38~41行出現了多態。

對變量polymophicBC來說,編譯時類型是BaseClass(聲明語句左端),運行時類型是SubClass(聲明語句右端)。

把一個子類對象賦給一個父類引用變量,在這個過程中發生了什么?

類型轉換

多態在Java中實現的機制就是把子類對象賦值給父類引用變量,這實際上就是一種類型裝換,具體也叫向上轉型(up-casting)。這種類型轉換由系統自動完成。

從聲明語句左邊來看:

  • BaseClass bc = new BaseClass();
  • BaseClass polymophicBC = new SubClass();

bcpolymophicBC都是BaseClass引用類型,但是它倆在執行同名函數test()時卻產生了不同的結果。這種調用同一個方法卻出現不同行為特征的現象,就是多態

多態機制下,父類引用變量在運行時總是調用子類的方法,也就是說呈現出子類的行為特征而不是父類的行為特征。

對象的實例變量不具有多態性。

  • 第39行,book仍然是父類的實例變量。

引用變量在編譯階段只能調用其編譯時類型擁有的方法,但是在運行時可以執行其運行時類型擁有的方法。

  • 第44行,BaseClass不具有sub()方法,因此不能調用,發生編譯錯誤;
  • 但第41行,BaseClass具有test()方法,因此可以調用,且在運行時執行的是SubClass的同名方法。

使用var時,并不能改變編譯時類型,因此也可能會發生多態:

var v1 = new SubClass(); // 自動推斷是SubClass,沒有多態
var v2 = polymophicBC(); // 賦值,v2自動推斷是BaseClass
// 此時調用sub方法,遵照多態機制,會發生編譯錯誤
// v2.sub();
強制類型轉換

按照上面規則,引用變量只能調用編譯時類型擁有的方法,即使它的運行時類型對象實際上包含了遠不止這些方法。

如何讓這個引用變量調用運行時類型所擁有的方法呢?

既然普通的多態依賴的是向上轉型,即把子類對象賦給父類引用變量,類似于我們把double基本變量賦給float。那么也可以反過來,執行強制類型轉換

強制類型轉換借助類型轉換運算符,和C++類似,就是()

類型轉換運算符可以實現基本類型之間的轉型,也能實現引用變量的轉型。

請注意,強制類型轉換不是萬能的,受到如下約束:

  • 基本類型之間轉型只能在數值類型中進行(整數型、字符型、浮點型)。數值型和布爾型之間不能轉換(C++中是可以的)。
  • 引用類型轉換只能在具有繼承關系(直接繼承或間接繼承都行)的類型之間進行。

強制類型轉換在這里,就是把父類實例轉換為子類類型。即其編譯時類型是父類類型,運行時類型是子類類型。這時候可以使用強制類型轉換。

public class ConversionTest
{public static void main(String[] args){var d = 13.4; // floatvar l = (long) d; // 強制類型轉換//------var in = 5; // int// var b = (boolean) in; // 錯誤,數值型不能轉換為布爾型//------Object obj = "Hello"; // 向上轉型,"Hello"是String,是Object的子類。這實際上就是多態,只不過這時候obj不能執行String擁有的方法var objStr = (String) obj; // 強制類型轉換,父類/基類和子類,正常System.out.println(objStr); // 做為String類型輸出//------Object objPri = Integer.valueOf(5); // 向上轉型,運行時類型是Integervar in = (Integer) objPri; // 強制類型轉換,基類和子類,正常// var str = (String) objPri; // objPri運行時時Integer,和String不存在繼承關系,運行時會報錯(類型轉換異常,ClassCastException)}
}

再解讀一下第12行:

  • objStr,雖然使用了var,但由于使用了強制類型轉換符(String),自動推斷它是String類型;
  • 此時objObject類型;
  • 因此,將obj賦值給objStr,實際上是把父類對象賦值給子類引用變量,這就和之前的upcasting正好相反,我們也可以稱之為downcasting
小結
  1. 把子類對象(右)賦給父類引用變量(左)時,觸發向上轉型,這種轉型是自動的、總是成功的。這種轉型表明這個引用變量編譯時是父類類型,運行時是子類類型。它表現出的是子類的行為方式,但是編譯時不能調用子類的方法。同時,實例變量仍然是父類的。
  2. 使用強制類型轉換可以把一個引用變量轉換成其子類類型。這種轉換必須是顯式的,而且不一定成功(若兩端不存在繼承關系)。
instanceof

使用instanceof運算符可以判斷是否可以執行類型轉換,以避免出現ClassCastException

if (objPri instanceof String)
{var str = (String) objPri;
}

instanceof用來判斷前面的對象是否是后面的類或者其子類的實例,是的話返回true,否則返回false

在Java 17中,為instanceof增加了快捷用法,來簡化上面的判斷代碼塊:

// 傳統instanceof,先判斷,再轉換,最后使用
if (obj instanceof String) // 先判斷
{var s = (String) obj; // 再轉換System.out.println(s.toUpperCase()); // 最后使用
}// Java 17的模式匹配,同時完成判斷和類型轉換
if (obj instanceof String s)
{System.out.println(s.toUpperCase());
}

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

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

相關文章

【Pytorch】Conda環境pack打包遷移報錯處理

文章目錄 Anaconda虛擬環境打包一、源電腦的環境打包1.安裝conda-pack工具2.確定環境3.打包環境4.將打包環境拷貝到U盤 二、環境遷移到目標電腦上三、異常處理pip install -e. 導致無法pack→忽略管理的文件已經被刪除或者被覆蓋→壓縮成tar注意 重新激活環境 Anaconda虛擬環境…

14 - matlab m_map地學繪圖工具基礎函數 - 一些數據轉換函數(一)

14 - matlab m_map地學繪圖工具基礎函數 - 一些數據轉換函數(一) 0. 引言1. 關于m_ll2xy和m_xy2ll2. 關于m_lldist3. 關于m_xydist4 關于m_fdist5 關于m_idist6. 總結 0. 引言 通過前面篇節已經將m_map繪圖工具中大多繪圖有關的函數進行過介紹&#xff0…

Nuxt3封裝網絡請求 useFetch $fetch

前言: 剛接觸、搭建Nuxt3項目的過程還是有點懵的,有種摸石頭過河的感覺,對于網絡請求這塊,與之前的Vue3項目有所區別,在Vue項目通常使用axios這個庫進行網絡請求,但在Nuxt項目并不推薦,因為有內…

RK3568平臺(顯示篇)主屏副屏配置

一.主屏副屏配置 目前在RK3568平臺上有兩路HDMIOUT輸出,分別輸出到兩個屏幕上,一路配置為主屏,一路配置為副屏。 硬件原理圖: &hdmi0_in_vp2 {status "okay"; };&hdmi1_in_vp0 {status "okay"; }…

【JAVA入門】Day15 - 接口

【JAVA入門】Day15 - 接口 文章目錄 【JAVA入門】Day15 - 接口一、接口是對“行為”的抽象二、接口的定義和使用三、接口中成員的特點四、接口和類之間的關系五、接口中新增的方法5.1 JDK8開始接口中新增的方法5.1.1 接口中的默認方法5.1.2 接口中的靜態方法 5.2 JDK9 開始接口…

Pandas實戰指南:any()函數深度解析與高效應用

Pandas實戰指南:any()函數深度解析與高效應用 引言 在數據分析和處理過程中,經常需要快速檢查數據集中是否存在滿足特定條件的元素。Pandas庫中的any()函數正是這樣一個強大的工具,它可以幫助我們沿著指定的軸檢查是否至少有一個元素滿足某…

Transformer重要論文與書籍 - Transformer教程

近年來,人工智能領域中的Transformer模型無疑成為了炙手可熱的研究對象。從自然語言處理(NLP)到計算機視覺,Transformer展現出了前所未有的強大能力。今天,我們將探討Tra在當今的人工智能和機器學習領域,Tr…

路由守衛中使用next()跳轉到指定路徑時會無限循環

路由守衛鉤子介紹 const router new VueRouter({ ... }) // 導航路由變化時觸發路由守衛鉤子 router.beforeEach((to, from, next) > {// ... }) to: Route: 即將要進入的目標路由對象(到哪去)from: Route: 當前導航正要離開的路由(從哪來)next: Function(必須&#xff0…

axios使用sm2加密數據后請求參數多了雙引號解決方法

axios使用sm2加密數據后請求參數多了雙引號解決 背景問題描述解決過程 背景 因項目安全要求,需對傳給后端的入參加密,將請求參數加密后再傳給后端 前期將axios降低到1.6.7后解決了問題,但最近axios有漏洞,安全要求對版本升級&…

從零開始[進階版]深入學習圖像分類:使用Python和TensorFlow

引言 圖像分類是計算機視覺中的一個核心任務,廣泛應用于人臉識別、自動駕駛、醫療影像分析等領域。在本篇文章中,我們將深入探討圖像分類的原理和實現,使用Python和TensorFlow搭建一個完整的圖像分類系統。本文不僅適合初學者,也…

【Qt 初識 Test】用圖形化和代碼的方式實現簡單的Qt程序

文章目錄 1. 通過圖形化的方式實現🍎2. 通過代碼的方式實現 1. 通過圖形化的方式實現🍎 在界面創建出一個控件,顯示 hello world,通過拖拽的方式實現; widget.ui文件如下:🔍 生成的 ui_widget.…

生物環保技術有哪些缺點或者局限性呢

生物環保技術,作為一種利用生物學原理和技術來處理環境污染的方法,雖然具有綠色環保、高效節能等優點,但也存在一些缺點和局限性。以下是對這些缺點和局限性的詳細分析: 一、受環境因素影響大 生物環保技術的效果往往受到環境因…

數據結構第18節 散列表 - 應用

散列表(Hash Table),也被稱為哈希表,是一種數據結構,它通過使用哈希函數將鍵映射到數組的某個位置來實現快速查找。散列表通常提供平均時間復雜度為O(1)的查找、插入和刪除操作,這使得它們在處理大量數據時…

【mybatis】mybatisX插件概述

一、主要功能 智能補全與提示 MyBatisX 可以智能地提示和補全 SQL 語句中的關鍵字、表名、列名等信息,從而顯著提高開發效率。代碼生成器 雖然 MyBatisX 本身可能不直接提供一個完整的、獨立的代碼生成器,但它可能集成了或支持與其他代碼生成工具&#…

鹵味江湖中,周黑鴨究竟該抓住什么賽點?

近年來,鹵味江湖的決斗從未停止。 隨著休閑鹵味、佐餐鹵味等細分賽道逐漸形成,“鹵味三巨頭”(周黑鴨、絕味食品、煌上煌)的牌桌上有了更多新對手,賽道變擠了,“周黑鴨們”也到了轉型關鍵期。 這個夏天&a…

MySQL字符串相關數據處理函數

目錄 1. 轉大小寫 2. 截取字符串 sunstr 3. 獲取字符長度 4. 字符串拼接 concat 5. 去掉空白 trim 1. 轉大小寫 轉大寫:upper() 轉小寫:lower() 雖然MySQL不嚴格區分大小寫,但是我們還是需要掌握這種大小寫的操作以方便學習其他…

python的入門知識(下)

目錄 學習內容數字字符串、列表和元組映射和集合類型 學習內容 數字 長整型(Long Integer): 在Python中,整數沒有大小限制,但是可以用大寫或小寫的L來表示長整型,盡管這不是Python 3推薦的做法。 復數(Co…

Nessus相關

tenable 1 安裝nessus scanner 1 )安裝nessus scanner: 方法一 curl -H X-Key: xxxxx https://cloud.tenable.com/install/scanner?namescanner-name&groupsscanner-group | bash方法二: **# for ubuntu, its https://www.tenable.com/downloads/api/v1/pu…

【JavaScript腳本宇宙】JavaScript 庫概覽:數字、貨幣值、日期時間處理一網打盡

簡化數據處理:掌握六大 JavaScript 庫的核心功能和使用技巧 前言 在現代的軟件開發中,處理數字、貨幣和日期時間是非常常見的需求。為了簡化這些任務,開發人員可以使用各種 JavaScript 庫來輕松地進行數字格式化、貨幣計算和日期時間操作。…

Google登錄時人機身份驗證的圖片類型和通過的經驗建議,以及一些常見問題

很多朋友在登錄谷歌賬號時,都遇到過要求人機身份驗證的步驟,而且有一些時候人機身份驗證這個步驟很讓人糾結,甚至壓根就出不來具體的驗證圖片,或者花了十幾分鐘、幾十分鐘都過不去。 所以今天GG賬號服務就來為您解析一下谷歌登錄…