- Kotlin 教程
- Kotlin - 主页
- Kotlin - 概述
- Kotlin - 环境设置
- Kotlin - 架构
- Kotlin - 基本语法
- Kotlin - 评论
- Kotlin - 关键字
- Kotlin - 变量
- Kotlin - 数据类型
- Kotlin - 运算符
- Kotlin - 布尔值
- Kotlin - 字符串
- Kotlin - 数组
- Kotlin - 范围
- Kotlin - 函数
- Kotlin 控制流程
- Kotlin - 控制流
- Kotlin - if...Else 表达式
- Kotlin - When 表达式
- Kotlin - For 循环
- Kotlin - While 循环
- Kotlin - 中断并继续
- Kotlin 集合
- Kotlin - 集合
- Kotlin - 列表
- Kotlin - 集
- Kotlin - 地图
- Kotlin 对象和类
- Kotlin - 类和对象
- Kotlin - 构造函数
- Kotlin - 继承
- Kotlin - 抽象类
- Kotlin - 接口
- Kotlin - 可见性控制
- Kotlin - 扩展
- Kotlin - 数据类
- Kotlin - 密封类
- Kotlin - 泛型
- Kotlin - 委托
- Kotlin - 解构声明
- Kotlin - 异常处理
- Kotlin 有用资源
- Kotlin - 快速指南
- Kotlin - 有用的资源
- Kotlin - 讨论
Kotlin - 继承
继承可以定义为一个类获取另一个类的成员(方法和属性)的过程。通过使用继承,信息可以按层次结构顺序进行管理。
继承其他类成员的类称为子类(派生类或子类),而其成员被继承的类称为超类(基类或父类)。
继承是面向对象编程的关键特征之一,它允许用户从现有类创建新类。继承我们可以继承基类的所有功能,并且还可以拥有自己的附加功能。
Kotlin 中的所有类都有一个名为Any 的公共超类,它是未声明超类型的类的默认超类:
class Example // Implicitly inherits from Any
Kotlin 超类Any具有三个方法:equals()、hashCode()和toString()。因此,这些方法是为所有 Kotlin 类定义的。
Kotlin 中的所有内容默认都是Final ,因此,我们需要在类声明前面使用关键字open ,使其可被其他类继承。Kotlin 使用运算符“:”来继承类。
例子:
看一下下面的继承示例。
open class ABC { fun think () { println("Hey!! i am thiking ") } } class BCD: ABC(){ // inheritence happend using default constructor } fun main(args: Array<String>) { var a = BCD() a.think() }
当你运行上面的 Kotlin 程序时,它将生成以下输出:
Hey!! i am thiking
重写方法
现在,如果我们想重写子类中的 think() 方法该怎么办?然后,我们需要考虑以下示例,其中我们创建两个类并将其函数之一重写到子类中。
open class ABC { open fun think () { println("Hey!! i am thinking ") } } class BCD: ABC() { // inheritance happens using default constructor override fun think() { println("I am from Child") } } fun main(args: Array<String>) { var a = BCD() a.think() }
当你运行上面的 Kotlin 程序时,它将生成以下输出:
I am from Child
用关键字override标记的成员本身是open,因此它可能会在子类中被覆盖。如果您想禁止重新覆盖它,那么您必须按如下方式将其定为最终版本:
class BCD: ABC() { final override fun think() { println("I am from Child") } }
重写属性
重写机制对属性的作用与对方法的作用相同。在超类上声明然后在派生类上重新声明的属性必须以关键字override开头,并且它们必须具有兼容的类型。
open class ABC { open val count: Int = 0 open fun think () { println("Hey!! i am thinking ") } } class BCD: ABC() { override val count: Int init{ count = 100 } override fun think() { println("I am from Child") } fun displayCount(){ println("Count value is $count") } } fun main(args: Array<String>) { var a = BCD() a.displayCount() }
当你运行上面的 Kotlin 程序时,它将生成以下输出:
Count value is 100
您还可以使用var属性覆盖val属性,但反之则不然。这是允许的,因为val属性本质上声明了一个 get 方法,并且将其重写为 var 会在派生类中另外声明一个 set 方法。
我们还可以使用override关键字作为主构造函数中属性声明的一部分。以下示例使用主构造函数来覆盖count属性,如果我们不向构造函数传递任何值,则默认值为 400:
open class ABC { open val count: Int = 0 open fun think () { println("Hey!! i am thinking ") } } class BCD(override val count: Int = 400): ABC() { override fun think() { println("I am from Child") } fun displayCount(){ println("Count value is $count") } } fun main(args: Array<String>) { var a = BCD(200) var b = BCD() a.displayCount() b.displayCount() }
当你运行上面的 Kotlin 程序时,它将生成以下输出:
Count value is 200 Count value is 400
派生类初始化顺序
当我们创建派生类的对象时,构造函数初始化从基类开始。这意味着首先将初始化所有基类属性,然后将调用任何派生类指导器,并且这同样适用于任何进一步的派生类。
这意味着当执行基类构造函数时,派生类中声明或重写的属性尚未初始化。
open class Base { init{ println("I am in Base class") } } open class Child: Base() { init{ println("I am in Child class") } } class GrandChild: Child() { init{ println("I am in Grand Child class") } } fun main(args: Array<String>) { var a = GrandChild() }
当你运行上面的 Kotlin 程序时,它将生成以下输出:
I am in Base class I am in Child class I am in Grand Child class
访问超级会员
派生类中的代码可以使用super关键字直接调用其超类函数和属性:
open class Base() { open val name:String init{ name = "Base" } open fun displayName(){ println("I am in " + this.name) } } class Child(): Base() { override fun displayName(){ super.displayName() println("I am in " + super.name) } } fun main(args: Array<String>) { var a = Child() a.displayName() }
当你运行上面的 Kotlin 程序时,它将生成以下输出:
I am in Base I am in Base
压倒一切的规则
如果子类从其直接超类继承同一成员的多个实现,则它必须重写该成员并提供自己的实现。
这与从单个父类继承成员的子类不同,在这种情况下,子类不强制提供所有开放成员的实现。
open class Rectangle { open fun draw() { /* ... */ } } interface Polygon { fun draw() { /* ... */ } // interface members are 'open' by default } class Square() : Rectangle(), Polygon { // The compiler requires draw() to be overridden: override fun draw() { super<Rectangle>.draw() // call to Rectangle.draw() super<Polygon>.draw() // call to Polygon.draw() } }
可以同时继承Rectangle和Polygon,但是它们都有各自的draw()方法的实现,因此您需要重写Square 中的draw()并为其提供单独的实现以消除歧义。
测验时间(面试和考试准备)
问题 2 - 从 Kotlin 继承的角度来看,哪种说法是正确的:
答案:D
解释
从 Kotlin 继承的角度来看,所有给出的陈述都是正确的。
问题 3 - 我们如何在子类中访问 Kotlin 父类成员?
答案:C
解释
给定关于访问子类中的父类成员的陈述 A 和 B 是正确的。