Kotlin 2.1.0 入門教程(十五)繼承、重寫、派生類初始化順序

繼承

所有類都有一個共同的超類 Any,對于沒有聲明超類型的類來說,Any 是其默認的超類:

// 隱式繼承自 Any。
class Example

Any 有三個方法:equals()hashCode()toString()。因此,所有類都定義了這些方法。

默認情況下,類是 final 的,即它們不能被繼承。若要使一個類可被繼承,需使用 open 關鍵字標記它:

// 該類可被繼承。
open class Base

要聲明一個顯式的超類型,在類頭中把類型放在冒號之后:

open class Base(p: Int)class Derived(p: Int) : Base(p)

如果派生類有主構造函數,基類必須根據其參數在該主構造函數中進行初始化。

如果派生類沒有主構造函數,那么每個次構造函數都必須使用 super 關鍵字來初始化基類型,或者委托給另一個能完成此操作的構造函數。注意,在這種情況下,不同的次構造函數可以調用基類型的不同構造函數:

class MyView : View {constructor(ctx: Context) : super(ctx)constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)
}

方法重寫

對可重寫的成員和重寫操作使用顯式修飾符:

open class Shape {open fun draw() { /*...*/ }fun fill() { /*...*/ }
}class Circle() : Shape() {override fun draw() { /*...*/ }
}

對于 Circle.draw() 方法,override 修飾符是必需的。如果缺少該修飾符,編譯器將會報錯。如果一個函數沒有 open 修飾符,比如 Shape.fill(),那么在子類中聲明具有相同簽名的方法是不允許的,無論是否使用 override 修飾符。對于 final 類(即沒有 open 修飾符的類)的成員,添加 open 修飾符是沒有效果的。

標記為 override 的成員本身是 open 的,因此它可以在子類中被再次重寫。如果你想禁止再次重寫,可以使用 final 修飾符:

open class Rectangle() : Shape() {final override fun draw() { /*...*/ }
}

屬性重寫

屬性的重寫機制和方法的重寫機制類似。在超類中聲明的屬性,若要在派生類中重新聲明,必須在前面加上 override 關鍵字,并且它們的類型必須兼容。每個已聲明的屬性可以被一個帶有初始值設定項的屬性或一個帶有 get 方法的屬性重寫:

open class Shape {open val vertexCount: Int = 0
}class Rectangle : Shape() {override val vertexCount = 4
}

你也可以用一個 var 屬性重寫一個 val 屬性,但反之則不行。這是允許的,因為 val 屬性本質上聲明了一個 get 方法,而將其重寫為 var 屬性時,還會在派生類中額外聲明一個 set 方法。

注意,你可以在主構造函數中把 override 關鍵字作為屬性聲明的一部分來使用:

interface Shape {val vertexCount: Int
}class Rectangle(override val vertexCount: Int = 4) : Shapeclass Polygon : Shape {override var vertexCount: Int = 0
}

派生類初始化順序

在創建派生類的新實例的過程中,基類的初始化是第一步(僅在對基類構造函數的參數求值之后進行),這意味著基類的初始化會在派生類的初始化邏輯執行之前完成。

open class Base(val name: String,) {init { println("Initializing a base class") }open val size: Int = name.length.also {println("Initializing size in the base class: $it")}
}class Derived(name: String, val lastName: String,): Base(name.replaceFirstChar { it.uppercase() }.also { println("Argument for the base class: $it") })
{init { println("Initializing a derived class") }override val size: Int = (super.size + lastName.length).also {println("Initializing size in the derived class: $it")}
}fun main() {// Argument for the base class: Aaa// Initializing a base class// Initializing size in the base class: 3// Initializing a derived class// Initializing size in the derived class: 6Derived("aaa", "bbb")
}

這意味著當基類構造函數執行時,派生類中聲明或重寫的屬性尚未初始化。在基類的初始化邏輯中使用這些屬性(無論是直接使用,還是通過另一個被重寫的開放成員的實現間接使用)可能會導致錯誤的行為或運行時故障。因此,在設計基類時,你應該避免在構造函數、屬性初始化器或初始化塊中使用開放成員。

調用超類實現

派生類中的代碼可以使用 super 關鍵字調用其超類的函數和屬性訪問器實現:

open class Rectangle {open fun draw() { println("Drawing a rectangle") }val borderColor: String get() = "black"
}class FilledRectangle : Rectangle() {override fun draw() {super.draw()println("Filling the rectangle")}val fillColor: String get() = super.borderColor
}

在內部類中,如果要訪問外部類的超類,可以使用帶有外部類名限定的 super 關鍵字,即 super@Outer 這種形式。下面通過具體的代碼示例來詳細解釋:

open class SuperClass {open fun doSomething() {println("SuperClass is doing something.")}
}class Outer : SuperClass() {override fun doSomething() {println("Outer class is doing something.")}inner class Inner {fun callSuperClassMethod() {super@Outer.doSomething() }}
}fun main() {// SuperClass is doing something.Outer().Inner().callSuperClassMethod()
}
open class SuperClass {open fun doSomething() {println("SuperClass is doing something.")}
}class Outer : SuperClass() {override fun doSomething() {println("Outer class is doing something.")}inner class Inner {fun callSuperClassMethod() {doSomething() }}
}fun main() {// Outer class is doing something.Outer().Inner().callSuperClassMethod()
}

重寫規則

實現繼承受以下規則約束:如果一個類從其直接超類繼承了同一成員的多個實現,那么它必須重寫該成員并提供自己的實現(也許可以使用其中一個繼承來的實現)。

為了指明從哪個超類型獲取繼承的實現,可以使用尖括號限定超類型名稱的 super,例如 super<Base>

open class Rectangle {open fun draw() {}
}interface Polygon {// 接口成員默認是 open 的。fun draw() {}
}class Square() : Rectangle(), Polygon {// 編譯器要求重寫 draw()。override fun draw() {super<Rectangle>.draw() // 調用 Rectangle 的 draw() 方法。super<Polygon>.draw() // 調用 Polygon 的 draw() 方法。}
}

RectanglePolygon 繼承是沒問題的,但是它們都有各自的 draw() 實現,所以需要在 Square 類中重寫 draw() 并提供一個單獨的實現來消除歧義。

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

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

相關文章

sqlilabs--小實驗

一、先盲注判斷 ?id1 and sleep(2)-- 如果發現頁面存在注點&#xff0c;使用時間盲注腳本進行注入 import requestsdef inject_database(url):name for i in range(1, 20): # 假設數據庫名稱長度不超過20low 48 # 0high 122 # zmiddle (low high) // 2while low &l…

【數字】異步FIFO面試的幾個小問題與跨時鐘域時序約束

入門數字設計的時候&#xff0c;跨時鐘域的數據處理是繞不開的課題&#xff0c;特別是多比特數據跨時鐘域時&#xff0c;都會采用異步FIFO的方法。 異步FIFO中涉及較多的考點這里記錄幾個以供大家參考。 1. 異步FIFO的空滿判斷分別在哪個域&#xff1f; 根據異步FIFO的結構&…

淺談Java Spring Boot 框架分析和理解

Spring Boot是一個簡化Spring開發的框架&#xff0c;它遵循“約定優于配置”的原則&#xff0c;通過內嵌的Tomcat、Jetty或Undertow等容器&#xff0c;使得開發者能夠快速構建獨立運行的、生產級別的基于Spring框架的應用程序。Spring Boot包含了大量的自動配置功能&#xff0c…

算法06-回溯算法

一、回溯算法詳解 回溯算法是一種通過逐步構建解決方案來解決問題的算法。它通常用于解決組合問題、排列問題、子集問題等。回溯算法的核心思想是“試錯”&#xff0c;即在每一步嘗試所有可能的選項&#xff0c;如果發現當前選擇無法達到目標&#xff0c;就回退到上一步&#…

RabbitMQ學習—day2—安裝

目錄 普通Linux安裝 安裝RabbitMQ 1、下載 2、安裝 3. Web管理界面及授權操作 Docker 安裝 強力推薦學docker&#xff0c;使用docker安裝 普通Linux安裝 安裝RabbitMQ 1、下載 官網下載地址&#xff1a;https://www.rabbitmq.com/download.html(opens new window) 這…

降本增效 - VGF 構建輕量高性能日志管理平臺

VFG 技術架構 Filebeat 接收Syslog &#xff0c;并進行日志分段&#xff0c;VictoriaLogs 持久化存儲日志 &#xff0c;Grafana 可視化、數據查詢、告警、數據導出。 為什么要用VictoriaLogs &#xff1f; 與Elasticsearch /Grafana Loki相比幾十倍的CPU/內存/存儲資源占用的…

初識camel智能體(一)

同目錄下配置環境變量.env&#xff0c;內容如下&#xff0c; apikey從魔搭社區獲取 QWEN_API_KEY4ff3ac8f-aebc******** 先上干貨代碼&#xff0c;主代碼如下&#xff1a; from colorama import Forefrom camel.societies import RolePlaying from camel.utils import prin…

介紹 Liquibase、Flyway、Talend 和 Apache NiFi:選擇適合的工具

在現代軟件開發中&#xff0c;尤其是在數據庫管理和數據集成方面&#xff0c;選擇合適的工具至關重要。本文將介紹四個流行的工具&#xff1a;Liquibase、Flyway、Talend 和 Apache NiFi&#xff0c;分析它們的應用、依賴以及如何選擇適合的工具。 1. Liquibase 簡介&#xff…

Docker使用指南與Dockerfile文件詳解:從入門到實戰

Docker使用指南與Dockerfile文件詳解:從入門到實戰 文章目錄 **Docker使用指南與Dockerfile文件詳解:從入門到實戰****引言****第一部分:Docker 核心概念速覽****1. Docker 基礎架構****2. Docker 核心命令****第二部分:Dockerfile 文件深度解析****1. Dockerfile 是什么?…

Qt工作總結03 <qSort按某一屬性進行排序>

1. 代碼樣例 QList<QGraphicsTextItem *> Lst;qSort(Lst.begin(),Lst.end(),[](const QGraphicsTextItem *itemA,const QGraphicsTextItem *itemB) {return itemA->toPlainText().toDouble() < itemB->toPlainText().toDouble(); }); 2. 參考 QList 按結構體…

深度學習|表示學習|Instance Normalization 全面總結|26

如是我聞&#xff1a; 1. Instance Normalization&#xff08;IN&#xff09; Instance Normalization&#xff08;IN&#xff09;最早由 Ulyanov et al.&#xff08;2017&#xff09; 提出&#xff0c;主要用于 風格遷移&#xff08;Style Transfer&#xff09; 任務。它的核…

如何保持 mysql 和 redis 中數據的一致性?PegaDB 給出答案

MySQL 與 Redis 數據保持一致性是一個常見且復雜的問題&#xff0c;一般來說需要結合多種策略來平衡性能與一致性。 傳統的解決策略是先讀緩存&#xff0c;未命中則讀數據庫并回填緩存&#xff0c;但方式這種維護成本較高。 隨著云數據庫技術的發展&#xff0c;目前國內云廠商…

探索ELK 的魅力

在大數據時代&#xff0c;海量日志和數據的收集、存儲、處理與可視化分析變得越來越重要。而 ELK 堆棧&#xff0c;由 Elasticsearch、Logstash、Beats 和 Kibana 組成&#xff0c;正是一個強大的開源解決方案&#xff0c;幫助開發者和運維人員高效管理和分析日志數據。本文將詳…

用vue3寫一個好看的wiki前端頁面

以下是一個使用 Vue 3 Element Plus 實現的 Wiki 風格前端頁面示例&#xff0c;包含現代設計、響應式布局和常用功能&#xff1a; <template><div class"wiki-container"><!-- 頭部導航 --><el-header class"wiki-header"><d…

深度學習實戰基礎案例——卷積神經網絡(CNN)基于DenseNet的眼疾檢測|第4例

文章目錄 前言一、數據準備二、項目實戰2.1 設置GPU2.2 數據加載2.3 數據預處理2.4 數據劃分2.5 搭建網絡模型2.6 構建densenet1212.7 訓練模型2.8 結果可視化 三、UI設計四、結果展示總結 前言 在當今社會&#xff0c;眼科疾病尤其是白內障對人們的視力健康構成了嚴重威脅。白…

DeepSeek的開源核爆:當技術民主化重構AI權力版圖

2025年2月&#xff0c;全球AI產業正經歷著由DeepSeek掀起的鏈式反應——這個首個開源千億參數多模態模型的企業&#xff0c;用開放戰略在技術壁壘森嚴的AI戰場投下"制度性核彈"。其貢獻不在于單純的技術突破&#xff0c;而在于通過開源協議實現了三重維度的大爆炸&am…

代碼隨想錄二叉樹篇(含源碼)

二叉樹與遞歸 前言226.翻轉二叉樹算法思路及代碼solution 1 用分解問題的思路來解決solution 2 用遍歷的思路來解決 101.對稱二叉樹算法思路及代碼solution 104.二叉樹的最大深度算法思路及代碼solution 1 遍歷solution 2 分解問題 111.二叉樹的最小深度算法思路及代碼solution…

MyBatis映射文件 <resultMap> 元素詳解與示例

引言 <resultMap> 是 MyBatis 中最核心的映射配置元素&#xff0c;用于解決數據庫字段與 Java 對象屬性之間的復雜映射問題&#xff0c;尤其是字段名不一致、嵌套對象關聯、集合映射等場景。ResultMap 的設計思想是&#xff0c;對簡單的語句做到零配置&#xff0c;對于復…

【xdoj離散數學上機】T283

遞歸函數易錯&#xff1a; 防止出現遞歸死循環&#xff01; 題目 題目&#xff1a;求誘導出的等價關系的關系矩陣 問題描述 給定有限集合上二元關系的關系矩陣&#xff0c;求由其誘導出的等價關系的關系矩陣。 輸入格式 第一行輸入n&#xff0c;表示矩陣為n階方陣&#xff0c…

WIN11上使用GraalVM打包springboot3項目為本地可執行文件exe

耐心肝才能成功 概念步驟概要詳細步驟一. GraalVM 17二. 安裝Visual Studio 2022三. 創建springboot四. IDEA最新版或者eclipse2025調試項目五. 打包exe 概念 springboot3生成的jar編譯成windows本地C文件&#xff0c;不再依賴JVM運行 WINDOW編譯較為復雜&#xff0c;限制條件…