- 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 - break 和 continue
- 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的,因此可以在子类中重写它。如果您想禁止再次重写它,则必须将其设为final,如下所示
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()并为其提供单独的实现以消除歧义。
测验时间 (面试和考试准备)
答案:C
解释
Kotlin 使用关键字open 使任何类或其成员可继承。
问2 - 从 Kotlin 继承的角度来看,哪个语句是正确的?
答案:D
解释
从 Kotlin 继承的角度来看,所有给定的语句都是正确的。
答案:C
解释
关于在子类中访问父类成员,给定的语句 A 和 B 是正确的。